Merge branch 'master' into 1.11
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "Engine/Engine/Globals.h"
|
||||
|
||||
ThreadLocal<bool> ContentDeprecatedFlags;
|
||||
|
||||
void ContentDeprecated::Mark()
|
||||
@@ -593,7 +595,7 @@ bool Asset::onLoad(LoadAssetTask* task)
|
||||
|
||||
#if USE_EDITOR
|
||||
// Auto-save deprecated assets to get rid of data in an old format
|
||||
if (isDeprecated && isLoaded)
|
||||
if (isDeprecated && isLoaded && !IsVirtual() && !GetPath().StartsWith(StringUtils::GetDirectoryName(Globals::TemporaryFolder)))
|
||||
{
|
||||
PROFILE_CPU_NAMED("Asset.Save");
|
||||
LOG(Info, "Resaving asset '{}' that uses deprecated data format", ToString());
|
||||
|
||||
@@ -326,7 +326,7 @@ bool Model::Init(const Span<int32>& meshesCountPerLod)
|
||||
lod.Link(this, lodIndex);
|
||||
lod.ScreenSize = 1.0f;
|
||||
const int32 meshesCount = meshesCountPerLod[lodIndex];
|
||||
if (meshesCount <= 0 || meshesCount > MODEL_MAX_MESHES)
|
||||
if (meshesCount < 0 || meshesCount > MODEL_MAX_MESHES)
|
||||
return true;
|
||||
|
||||
lod.Meshes.Resize(meshesCount);
|
||||
@@ -365,7 +365,7 @@ bool Model::LoadHeader(ReadStream& stream, byte& headerVersion)
|
||||
// Meshes
|
||||
uint16 meshesCount;
|
||||
stream.ReadUint16(&meshesCount);
|
||||
if (meshesCount == 0 || meshesCount > MODEL_MAX_MESHES)
|
||||
if (meshesCount > MODEL_MAX_MESHES)
|
||||
return true;
|
||||
ASSERT(lodIndex == 0 || LODs[0].Meshes.Count() >= meshesCount);
|
||||
lod.Meshes.Resize(meshesCount, false);
|
||||
|
||||
@@ -669,6 +669,8 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
Array<GPUVertexLayout::Elements, FixedAllocation<MODEL_MAX_VB>> vbElements;
|
||||
const bool useSeparatePositions = !isSkinned;
|
||||
const bool useSeparateColors = !isSkinned;
|
||||
PixelFormat positionsFormat = modelData.PositionFormat == ModelData::PositionFormats::Float32 ? PixelFormat::R32G32B32_Float : PixelFormat::R16G16B16A16_Float;
|
||||
PixelFormat texCoordsFormat = modelData.TexCoordFormat == ModelData::TexCoordFormats::Float16 ? PixelFormat::R16G16_Float : PixelFormat::R8G8_UNorm;
|
||||
PixelFormat blendIndicesFormat = PixelFormat::R8G8B8A8_UInt;
|
||||
PixelFormat blendWeightsFormat = PixelFormat::R8G8B8A8_UNorm;
|
||||
for (const Int4& indices : mesh.BlendIndices)
|
||||
@@ -681,14 +683,13 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
}
|
||||
{
|
||||
byte vbIndex = 0;
|
||||
// TODO: add option to quantize vertex positions (eg. 16-bit)
|
||||
// TODO: add option to quantize vertex attributes (eg. 8-bit blend weights, 8-bit texcoords)
|
||||
|
||||
// Position
|
||||
if (useSeparatePositions)
|
||||
{
|
||||
auto& vb0 = vbElements.AddOne();
|
||||
vb0.Add({ VertexElement::Types::Position, vbIndex, 0, 0, PixelFormat::R32G32B32_Float });
|
||||
vb0.Add({ VertexElement::Types::Position, vbIndex, 0, 0, positionsFormat });
|
||||
vbIndex++;
|
||||
}
|
||||
|
||||
@@ -696,13 +697,13 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
{
|
||||
auto& vb = vbElements.AddOne();
|
||||
if (!useSeparatePositions)
|
||||
vb.Add({ VertexElement::Types::Position, vbIndex, 0, 0, PixelFormat::R32G32B32_Float });
|
||||
vb.Add({ VertexElement::Types::Position, vbIndex, 0, 0, positionsFormat });
|
||||
for (int32 channelIdx = 0; channelIdx < mesh.UVs.Count(); channelIdx++)
|
||||
{
|
||||
auto& channel = mesh.UVs.Get()[channelIdx];
|
||||
if (channel.HasItems())
|
||||
{
|
||||
vb.Add({ (VertexElement::Types)((int32)VertexElement::Types::TexCoord0 + channelIdx), vbIndex, 0, 0, PixelFormat::R16G16_Float });
|
||||
vb.Add({ (VertexElement::Types)((int32)VertexElement::Types::TexCoord0 + channelIdx), vbIndex, 0, 0, texCoordsFormat });
|
||||
}
|
||||
}
|
||||
vb.Add({ VertexElement::Types::Normal, vbIndex, 0, 0, PixelFormat::R10G10B10A2_UNorm });
|
||||
@@ -737,7 +738,7 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
// Write vertex buffers
|
||||
for (int32 vbIndex = 0; vbIndex < vbCount; vbIndex++)
|
||||
{
|
||||
if (useSeparatePositions && vbIndex == 0)
|
||||
if (useSeparatePositions && vbIndex == 0 && positionsFormat == PixelFormat::R32G32B32_Float)
|
||||
{
|
||||
// Fast path for vertex positions of static models using the first buffer
|
||||
stream.WriteBytes(mesh.Positions.Get(), sizeof(Float3) * vertices);
|
||||
@@ -755,7 +756,15 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
case VertexElement::Types::Position:
|
||||
{
|
||||
const Float3 position = mesh.Positions.Get()[vertex];
|
||||
stream.Write(position);
|
||||
if (positionsFormat == PixelFormat::R16G16B16A16_Float)
|
||||
{
|
||||
const Half4 positionEnc(Float4(position, 0.0f));
|
||||
stream.Write(positionEnc);
|
||||
}
|
||||
else //if (positionsFormat == PixelFormat::R32G32B32_Float)
|
||||
{
|
||||
stream.Write(position);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VertexElement::Types::Color:
|
||||
@@ -821,8 +830,16 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
{
|
||||
const int32 channelIdx = (int32)element.Type - (int32)VertexElement::Types::TexCoord0;
|
||||
const Float2 uv = mesh.UVs.Get()[channelIdx].Get()[vertex];
|
||||
const Half2 uvEnc(uv);
|
||||
stream.Write(uvEnc);
|
||||
if (texCoordsFormat == PixelFormat::R8G8_UNorm)
|
||||
{
|
||||
stream.Write((uint8)Math::Clamp<int32>((int32)(uv.X * 255), 0, 255));
|
||||
stream.Write((uint8)Math::Clamp<int32>((int32)(uv.Y * 255), 0, 255));
|
||||
}
|
||||
else //if (texCoordsFormat == PixelFormat::R16G16_Float)
|
||||
{
|
||||
const Half2 uvEnc(uv);
|
||||
stream.Write(uvEnc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -478,7 +478,7 @@ bool SkinnedModel::Init(const Span<int32>& meshesCountPerLod)
|
||||
lod._lodIndex = lodIndex;
|
||||
lod.ScreenSize = 1.0f;
|
||||
const int32 meshesCount = meshesCountPerLod[lodIndex];
|
||||
if (meshesCount <= 0 || meshesCount > MODEL_MAX_MESHES)
|
||||
if (meshesCount < 0 || meshesCount > MODEL_MAX_MESHES)
|
||||
return true;
|
||||
|
||||
lod.Meshes.Resize(meshesCount);
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
#include "Engine/Level/Types.h"
|
||||
#include "Engine/Debug/Exceptions/JsonParseException.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Core/Collections/HashSet.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#endif
|
||||
#include <ThirdParty/rapidjson/document.h>
|
||||
|
||||
bool JsonStorageProxy::IsValidExtension(const StringView& extension)
|
||||
@@ -56,27 +60,31 @@ bool JsonStorageProxy::GetAssetInfo(const StringView& path, Guid& resultId, Stri
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void ChangeIds(rapidjson_flax::Value& obj, rapidjson_flax::Document& document, const StringAnsi& srcId, const StringAnsi& dstId)
|
||||
void FindObjectIds(const rapidjson_flax::Value& obj, const rapidjson_flax::Document& document, HashSet<Guid>& ids, const char* parentName = nullptr)
|
||||
{
|
||||
if (obj.IsObject())
|
||||
{
|
||||
for (rapidjson_flax::Value::MemberIterator i = obj.MemberBegin(); i != obj.MemberEnd(); ++i)
|
||||
for (rapidjson_flax::Value::ConstMemberIterator i = obj.MemberBegin(); i != obj.MemberEnd(); ++i)
|
||||
{
|
||||
ChangeIds(i->value, document, srcId, dstId);
|
||||
FindObjectIds(i->value, document, ids, i->name.GetString());
|
||||
}
|
||||
}
|
||||
else if (obj.IsArray())
|
||||
{
|
||||
for (rapidjson::SizeType i = 0; i < obj.Size(); i++)
|
||||
{
|
||||
ChangeIds(obj[i], document, srcId, dstId);
|
||||
FindObjectIds(obj[i], document, ids, parentName);
|
||||
}
|
||||
}
|
||||
else if (obj.IsString())
|
||||
else if (obj.IsString() && obj.GetStringLength() == 32)
|
||||
{
|
||||
if (StringUtils::Compare(srcId.Get(), obj.GetString()) == 0)
|
||||
if (parentName && StringUtils::Compare(parentName, "ID") == 0)
|
||||
{
|
||||
obj.SetString(dstId.Get(), document.GetAllocator());
|
||||
auto value = JsonTools::GetGuid(obj);
|
||||
if (value.IsValid())
|
||||
{
|
||||
ids.Add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,9 +99,7 @@ bool JsonStorageProxy::ChangeId(const StringView& path, const Guid& newId)
|
||||
// Load file
|
||||
Array<byte> fileData;
|
||||
if (File::ReadAllBytes(path, fileData))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse data
|
||||
rapidjson_flax::Document document;
|
||||
@@ -107,33 +113,35 @@ bool JsonStorageProxy::ChangeId(const StringView& path, const Guid& newId)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try get asset metadata
|
||||
// Get all IDs inside the file
|
||||
HashSet<Guid> ids;
|
||||
FindObjectIds(document, document, ids);
|
||||
|
||||
// Remap into a unique IDs
|
||||
Dictionary<Guid, Guid> remap;
|
||||
remap.EnsureCapacity(ids.Count());
|
||||
for (const auto& id : ids)
|
||||
remap.Add(id.Item, Guid::New());
|
||||
|
||||
// Remap asset ID using the provided value
|
||||
auto idNode = document.FindMember("ID");
|
||||
if (idNode == document.MemberEnd())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
remap[JsonTools::GetGuid(idNode->value)] = newId;
|
||||
|
||||
// Change IDs
|
||||
auto oldIdStr = idNode->value.GetString();
|
||||
auto newIdStr = newId.ToString(Guid::FormatType::N).ToStringAnsi();
|
||||
ChangeIds(document, document, oldIdStr, newIdStr);
|
||||
// Change IDs of asset and objects inside asset
|
||||
JsonTools::ChangeIds(document, remap);
|
||||
|
||||
// Save to file
|
||||
rapidjson_flax::StringBuffer buffer;
|
||||
PrettyJsonWriter writer(buffer);
|
||||
document.Accept(writer.GetWriter());
|
||||
if (File::WriteAllBytes(path, (byte*)buffer.GetString(), (int32)buffer.GetSize()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
#else
|
||||
|
||||
LOG(Warning, "Editing cooked content is invalid.");
|
||||
return true;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -673,23 +673,23 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Vector4" /> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Vector4" /> to compare with this instance.</param>
|
||||
/// <param name="other">The <see cref="Vector4" /> to compare with this instance.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(ref BoundingBox value)
|
||||
public bool Equals(ref BoundingBox other)
|
||||
{
|
||||
return Minimum == value.Minimum && Maximum == value.Maximum;
|
||||
return Minimum == other.Minimum && Maximum == other.Maximum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Vector4" /> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Vector4" /> to compare with this instance.</param>
|
||||
/// <param name="other">The <see cref="Vector4" /> to compare with this instance.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(BoundingBox value)
|
||||
public bool Equals(BoundingBox other)
|
||||
{
|
||||
return Equals(ref value);
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -487,23 +487,23 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Vector4" /> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Vector4" /> to compare with this instance.</param>
|
||||
/// <param name="other">The <see cref="Vector4" /> to compare with this instance.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(ref BoundingSphere value)
|
||||
public bool Equals(ref BoundingSphere other)
|
||||
{
|
||||
return (Center == value.Center) && (Radius == value.Radius);
|
||||
return Center == other.Center && Radius == other.Radius;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Vector4" /> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Vector4" /> to compare with this instance.</param>
|
||||
/// <param name="other">The <see cref="Vector4" /> to compare with this instance.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(BoundingSphere value)
|
||||
public bool Equals(BoundingSphere other)
|
||||
{
|
||||
return Equals(ref value);
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -197,12 +197,9 @@ namespace FlaxEngine
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Equals(object other)
|
||||
public override bool Equals(object value)
|
||||
{
|
||||
if (!(other is Color))
|
||||
return false;
|
||||
var color = (Color)other;
|
||||
return Equals(ref color);
|
||||
return value is Color other && Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -213,7 +210,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(ref Color other)
|
||||
{
|
||||
return Mathf.NearEqual(other.R, R) && Mathf.NearEqual(other.G, G) && Mathf.NearEqual(other.B, B) && Mathf.NearEqual(other.A, A);
|
||||
return R == other.R && G == other.G && B == other.B && A == other.A;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -661,23 +658,23 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Compares two colors.
|
||||
/// </summary>
|
||||
/// <param name="lhs">The left.</param>
|
||||
/// <param name="rhs">The right.</param>
|
||||
/// <param name="left">The left.</param>
|
||||
/// <param name="right">The right.</param>
|
||||
/// <returns>True if colors are equal, otherwise false.</returns>
|
||||
public static bool operator ==(Color lhs, Color rhs)
|
||||
public static bool operator ==(Color left, Color right)
|
||||
{
|
||||
return lhs.Equals(ref rhs);
|
||||
return left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares two colors.
|
||||
/// </summary>
|
||||
/// <param name="lhs">The left.</param>
|
||||
/// <param name="rhs">The right.</param>
|
||||
/// <param name="left">The left.</param>
|
||||
/// <param name="right">The right.</param>
|
||||
/// <returns>True if colors are not equal, otherwise false.</returns>
|
||||
public static bool operator !=(Color lhs, Color rhs)
|
||||
public static bool operator !=(Color left, Color right)
|
||||
{
|
||||
return !lhs.Equals(ref rhs);
|
||||
return !left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1464,7 +1464,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Double2 left, Double2 right)
|
||||
{
|
||||
return Mathd.NearEqual(left.X, right.X) && Mathd.NearEqual(left.Y, right.Y);
|
||||
return left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1476,7 +1476,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(Double2 left, Double2 right)
|
||||
{
|
||||
return !Mathd.NearEqual(left.X, right.X) || !Mathd.NearEqual(left.Y, right.Y);
|
||||
return !left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1582,7 +1582,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(ref Double2 other)
|
||||
{
|
||||
return Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y);
|
||||
return X == other.X && Y == other.Y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1590,7 +1590,7 @@ namespace FlaxEngine
|
||||
/// </summary>
|
||||
public static bool Equals(ref Double2 a, ref Double2 b)
|
||||
{
|
||||
return Mathd.NearEqual(a.X, b.X) && Mathd.NearEqual(a.Y, b.Y);
|
||||
return a.Equals(ref b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1601,7 +1601,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(Double2 other)
|
||||
{
|
||||
return Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y);
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1611,7 +1611,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object value)
|
||||
{
|
||||
return value is Double2 other && Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y);
|
||||
return value is Double2 other && Equals(ref other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1759,7 +1759,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Double3 left, Double3 right)
|
||||
{
|
||||
return Mathd.NearEqual(left.X, right.X) && Mathd.NearEqual(left.Y, right.Y) && Mathd.NearEqual(left.Z, right.Z);
|
||||
return left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1771,7 +1771,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(Double3 left, Double3 right)
|
||||
{
|
||||
return !Mathd.NearEqual(left.X, right.X) || !Mathd.NearEqual(left.Y, right.Y) || !Mathd.NearEqual(left.Z, right.Z);
|
||||
return !left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1880,7 +1880,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(ref Double3 other)
|
||||
{
|
||||
return Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y) && Mathd.NearEqual(other.Z, Z);
|
||||
return X == other.X && Y == other.Y && Z == other.Z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1891,7 +1891,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(Double3 other)
|
||||
{
|
||||
return Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y) && Mathd.NearEqual(other.Z, Z);
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1901,7 +1901,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object value)
|
||||
{
|
||||
return value is Double3 other && Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y) && Mathd.NearEqual(other.Z, Z);
|
||||
return value is Double3 other && Equals(ref other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1258,7 +1258,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Double4 left, Double4 right)
|
||||
{
|
||||
return Mathd.NearEqual(left.X, right.X) && Mathd.NearEqual(left.Y, right.Y) && Mathd.NearEqual(left.Z, right.Z) && Mathd.NearEqual(left.W, right.W);
|
||||
return left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1379,7 +1379,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="Double4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public bool Equals(ref Double4 other)
|
||||
{
|
||||
return Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y) && Mathd.NearEqual(other.Z, Z) && Mathd.NearEqual(other.W, W);
|
||||
return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1390,7 +1390,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(Double4 other)
|
||||
{
|
||||
return Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y) && Mathd.NearEqual(other.Z, Z) && Mathd.NearEqual(other.W, W);
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1400,7 +1400,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object value)
|
||||
{
|
||||
return value is Double4 other && Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y) && Mathd.NearEqual(other.Z, Z) && Mathd.NearEqual(other.W, W);
|
||||
return value is Double4 other && Equals(ref other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1540,7 +1540,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Float2 left, Float2 right)
|
||||
{
|
||||
return Mathf.NearEqual(left.X, right.X) && Mathf.NearEqual(left.Y, right.Y);
|
||||
return left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1552,7 +1552,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(Float2 left, Float2 right)
|
||||
{
|
||||
return !Mathf.NearEqual(left.X, right.X) || !Mathf.NearEqual(left.Y, right.Y);
|
||||
return !left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1658,7 +1658,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(ref Float2 other)
|
||||
{
|
||||
return Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y);
|
||||
return X == other.X && Y == other.Y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1666,7 +1666,7 @@ namespace FlaxEngine
|
||||
/// </summary>
|
||||
public static bool Equals(ref Float2 a, ref Float2 b)
|
||||
{
|
||||
return Mathf.NearEqual(a.X, b.X) && Mathf.NearEqual(a.Y, b.Y);
|
||||
return a.Equals(ref b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1677,7 +1677,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(Float2 other)
|
||||
{
|
||||
return Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y);
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1687,7 +1687,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object value)
|
||||
{
|
||||
return value is Float2 other && Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y);
|
||||
return value is Float2 other && Equals(ref other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1791,7 +1791,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Float3 left, Float3 right)
|
||||
{
|
||||
return Mathf.NearEqual(left.X, right.X) && Mathf.NearEqual(left.Y, right.Y) && Mathf.NearEqual(left.Z, right.Z);
|
||||
return left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1803,7 +1803,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(Float3 left, Float3 right)
|
||||
{
|
||||
return !Mathf.NearEqual(left.X, right.X) || !Mathf.NearEqual(left.Y, right.Y) || !Mathf.NearEqual(left.Z, right.Z);
|
||||
return !left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1912,7 +1912,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(ref Float3 other)
|
||||
{
|
||||
return Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y) && Mathf.NearEqual(other.Z, Z);
|
||||
return X == other.X && Y == other.Y && Z == other.Z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1923,7 +1923,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(Float3 other)
|
||||
{
|
||||
return Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y) && Mathf.NearEqual(other.Z, Z);
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1933,7 +1933,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object value)
|
||||
{
|
||||
return value is Float3 other && Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y) && Mathf.NearEqual(other.Z, Z);
|
||||
return value is Float3 other && Equals(ref other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1288,7 +1288,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Float4 left, Float4 right)
|
||||
{
|
||||
return Mathf.NearEqual(left.X, right.X) && Mathf.NearEqual(left.Y, right.Y) && Mathf.NearEqual(left.Z, right.Z) && Mathf.NearEqual(left.W, right.W);
|
||||
return left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1419,7 +1419,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="Float4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public bool Equals(ref Float4 other)
|
||||
{
|
||||
return Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y) && Mathf.NearEqual(other.Z, Z) && Mathf.NearEqual(other.W, W);
|
||||
return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1430,7 +1430,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(Float4 other)
|
||||
{
|
||||
return Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y) && Mathf.NearEqual(other.Z, Z) && Mathf.NearEqual(other.W, W);
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1440,7 +1440,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object value)
|
||||
{
|
||||
return value is Float4 other && Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y) && Mathf.NearEqual(other.Z, Z) && Mathf.NearEqual(other.W, W);
|
||||
return value is Float4 other && Equals(ref other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ bool Matrix::operator==(const Matrix& other) const
|
||||
{
|
||||
for (int32 i = 0; i < 16; i++)
|
||||
{
|
||||
if (Math::NotNearEqual(other.Raw[i], Raw[i]))
|
||||
if (other.Raw[i] != Raw[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -3236,22 +3236,22 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="Matrix" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public bool Equals(ref Matrix other)
|
||||
{
|
||||
return Mathf.NearEqual(other.M11, M11) &&
|
||||
Mathf.NearEqual(other.M12, M12) &&
|
||||
Mathf.NearEqual(other.M13, M13) &&
|
||||
Mathf.NearEqual(other.M14, M14) &&
|
||||
Mathf.NearEqual(other.M21, M21) &&
|
||||
Mathf.NearEqual(other.M22, M22) &&
|
||||
Mathf.NearEqual(other.M23, M23) &&
|
||||
Mathf.NearEqual(other.M24, M24) &&
|
||||
Mathf.NearEqual(other.M31, M31) &&
|
||||
Mathf.NearEqual(other.M32, M32) &&
|
||||
Mathf.NearEqual(other.M33, M33) &&
|
||||
Mathf.NearEqual(other.M34, M34) &&
|
||||
Mathf.NearEqual(other.M41, M41) &&
|
||||
Mathf.NearEqual(other.M42, M42) &&
|
||||
Mathf.NearEqual(other.M43, M43) &&
|
||||
Mathf.NearEqual(other.M44, M44);
|
||||
return other.M11 == M11 &&
|
||||
other.M12 == M12 &&
|
||||
other.M13 == M13 &&
|
||||
other.M14 == M14 &&
|
||||
other.M21 == M21 &&
|
||||
other.M22 == M22 &&
|
||||
other.M23 == M23 &&
|
||||
other.M24 == M24 &&
|
||||
other.M31 == M31 &&
|
||||
other.M32 == M32 &&
|
||||
other.M33 == M33 &&
|
||||
other.M34 == M34 &&
|
||||
other.M41 == M41 &&
|
||||
other.M42 == M42 &&
|
||||
other.M43 == M43 &&
|
||||
other.M44 == M44;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -3272,10 +3272,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object value)
|
||||
{
|
||||
if (!(value is Matrix))
|
||||
return false;
|
||||
var v = (Matrix)value;
|
||||
return Equals(ref v);
|
||||
return value is Matrix other && Equals(ref other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,7 +483,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="Matrix2x2"/> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public bool Equals(ref Matrix2x2 other)
|
||||
{
|
||||
return Mathf.NearEqual(other.M11, M11) && Mathf.NearEqual(other.M12, M12) && Mathf.NearEqual(other.M21, M21) && Mathf.NearEqual(other.M22, M22);
|
||||
return M11 == other.M11 && M12 == other.M12 && M21 == other.M21 && M22 == other.M22;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -502,7 +502,7 @@ namespace FlaxEngine
|
||||
/// </summary>
|
||||
public static bool Equals(ref Matrix2x2 a, ref Matrix2x2 b)
|
||||
{
|
||||
return Mathf.NearEqual(a.M11, b.M11) && Mathf.NearEqual(a.M12, b.M12) && Mathf.NearEqual(a.M21, b.M21) && Mathf.NearEqual(a.M22, b.M22);
|
||||
return a.Equals(ref b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -242,14 +242,13 @@ void Matrix3x3::Decompose(Float3& scale, Quaternion& rotation) const
|
||||
|
||||
bool Matrix3x3::operator==(const Matrix3x3& other) const
|
||||
{
|
||||
return
|
||||
Math::NearEqual(M11, other.M11) &&
|
||||
Math::NearEqual(M12, other.M12) &&
|
||||
Math::NearEqual(M13, other.M13) &&
|
||||
Math::NearEqual(M21, other.M21) &&
|
||||
Math::NearEqual(M22, other.M22) &&
|
||||
Math::NearEqual(M23, other.M23) &&
|
||||
Math::NearEqual(M31, other.M31) &&
|
||||
Math::NearEqual(M32, other.M32) &&
|
||||
Math::NearEqual(M33, other.M33);
|
||||
return M11 == other.M11 &&
|
||||
M12 == other.M12 &&
|
||||
M13 == other.M13 &&
|
||||
M21 == other.M21 &&
|
||||
M22 == other.M22 &&
|
||||
M23 == other.M23 &&
|
||||
M31 == other.M31 &&
|
||||
M32 == other.M32 &&
|
||||
M33 == other.M33;
|
||||
}
|
||||
|
||||
@@ -2125,15 +2125,15 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="Matrix3x3"/> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public bool Equals(ref Matrix3x3 other)
|
||||
{
|
||||
return (Mathf.NearEqual(other.M11, M11) &&
|
||||
Mathf.NearEqual(other.M12, M12) &&
|
||||
Mathf.NearEqual(other.M13, M13) &&
|
||||
Mathf.NearEqual(other.M21, M21) &&
|
||||
Mathf.NearEqual(other.M22, M22) &&
|
||||
Mathf.NearEqual(other.M23, M23) &&
|
||||
Mathf.NearEqual(other.M31, M31) &&
|
||||
Mathf.NearEqual(other.M32, M32) &&
|
||||
Mathf.NearEqual(other.M33, M33));
|
||||
return M11 == other.M11 &&
|
||||
M12 == other.M12 &&
|
||||
M13 == other.M13 &&
|
||||
M21 == other.M21 &&
|
||||
M22 == other.M22 &&
|
||||
M23 == other.M23 &&
|
||||
M31 == other.M31 &&
|
||||
M32 == other.M32 &&
|
||||
M33 == other.M33;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2152,17 +2152,7 @@ namespace FlaxEngine
|
||||
/// </summary>
|
||||
public static bool Equals(ref Matrix3x3 a, ref Matrix3x3 b)
|
||||
{
|
||||
return
|
||||
Mathf.NearEqual(a.M11, b.M11) &&
|
||||
Mathf.NearEqual(a.M12, b.M12) &&
|
||||
Mathf.NearEqual(a.M13, b.M13) &&
|
||||
Mathf.NearEqual(a.M21, b.M21) &&
|
||||
Mathf.NearEqual(a.M22, b.M22) &&
|
||||
Mathf.NearEqual(a.M23, b.M23) &&
|
||||
Mathf.NearEqual(a.M31, b.M31) &&
|
||||
Mathf.NearEqual(a.M32, b.M32) &&
|
||||
Mathf.NearEqual(a.M33, b.M33)
|
||||
;
|
||||
return a.Equals(ref b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -397,7 +397,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(ref OrientedBoundingBox value)
|
||||
{
|
||||
return (Extents == value.Extents) && (Transformation == value.Transformation);
|
||||
return Extents == value.Extents && Transformation == value.Transformation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -582,23 +582,23 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Vector4" /> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Vector4" /> to compare with this instance.</param>
|
||||
/// <param name="other">The <see cref="Vector4" /> to compare with this instance.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(ref Plane value)
|
||||
public bool Equals(ref Plane other)
|
||||
{
|
||||
return Normal == value.Normal && D == value.D;
|
||||
return Normal == other.Normal && D == other.D;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Vector4" /> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Vector4" /> to compare with this instance.</param>
|
||||
/// <param name="other">The <see cref="Vector4" /> to compare with this instance.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(Plane value)
|
||||
public bool Equals(Plane other)
|
||||
{
|
||||
return Equals(ref value);
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -608,10 +608,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object value)
|
||||
{
|
||||
if (!(value is Plane))
|
||||
return false;
|
||||
var strongValue = (Plane)value;
|
||||
return Equals(ref strongValue);
|
||||
return value is Plane other && Equals(ref other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1149,7 +1149,7 @@ namespace FlaxEngine
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the quaternion that will rotate vector from into vector to, around their plan perpendicular axis.The input vectors don't need to be normalized.
|
||||
/// Gets the quaternion that will rotate vector from into vector to, around their plan perpendicular axis. The input vectors don't need to be normalized.
|
||||
/// </summary>
|
||||
/// <param name="from">The source vector.</param>
|
||||
/// <param name="to">The destination vector.</param>
|
||||
@@ -1179,7 +1179,7 @@ namespace FlaxEngine
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the quaternion that will rotate vector from into vector to, around their plan perpendicular axis.The input vectors don't need to be normalized.
|
||||
/// Gets the quaternion that will rotate the from into vector to, around their plan perpendicular axis. The input vectors don't need to be normalized.
|
||||
/// </summary>
|
||||
/// <param name="from">The source vector.</param>
|
||||
/// <param name="to">The destination vector.</param>
|
||||
@@ -1602,7 +1602,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Quaternion left, Quaternion right)
|
||||
{
|
||||
return Dot(ref left, ref right) > Tolerance;
|
||||
return left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1614,7 +1614,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(Quaternion left, Quaternion right)
|
||||
{
|
||||
return Dot(ref left, ref right) <= Tolerance;
|
||||
return !left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1714,8 +1714,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(ref Quaternion other)
|
||||
{
|
||||
//return Dot(ref this, ref other) > Tolerance;
|
||||
return Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y) && Mathf.NearEqual(other.Z, Z) && Mathf.NearEqual(other.W, W);
|
||||
return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1736,10 +1735,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object value)
|
||||
{
|
||||
if (!(value is Quaternion))
|
||||
return false;
|
||||
var strongValue = (Quaternion)value;
|
||||
return Equals(ref strongValue);
|
||||
return value is Quaternion other && Equals(ref other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,7 +348,7 @@ public:
|
||||
/// <returns><c>true</c> if the specified <see cref="Quaternion" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
FORCE_INLINE bool operator==(const Quaternion& other) const
|
||||
{
|
||||
return Dot(*this, other) > Tolerance;
|
||||
return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -358,7 +358,7 @@ public:
|
||||
/// <returns><c>true</c> if the specified <see cref="Quaternion" /> isn't equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
FORCE_INLINE bool operator!=(const Quaternion& other) const
|
||||
{
|
||||
return Dot(*this, other) < Tolerance;
|
||||
return X != other.X || Y != other.Y || Z != other.Z || W != other.W;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@@ -428,23 +428,23 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Vector4" /> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Vector4" /> to compare with this instance.</param>
|
||||
/// <param name="other">The <see cref="Vector4" /> to compare with this instance.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(ref Ray value)
|
||||
public bool Equals(ref Ray other)
|
||||
{
|
||||
return (Position == value.Position) && (Direction == value.Direction);
|
||||
return Position == other.Position && Direction == other.Direction;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Vector4" /> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Vector4" /> to compare with this instance.</param>
|
||||
/// <param name="other">The <see cref="Vector4" /> to compare with this instance.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(Ray value)
|
||||
public bool Equals(Ray other)
|
||||
{
|
||||
return Equals(ref value);
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -499,21 +499,19 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(ref Rectangle other)
|
||||
{
|
||||
return Location.Equals(ref other.Location) && Size.Equals(ref other.Size);
|
||||
return Location == other.Location && Size == other.Size;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Equals(Rectangle other)
|
||||
{
|
||||
return Location.Equals(ref other.Location) && Size.Equals(ref other.Size);
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj))
|
||||
return false;
|
||||
return obj is Rectangle && Equals((Rectangle)obj);
|
||||
return obj is Rectangle other && Equals(ref other);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -1654,7 +1654,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Vector2 left, Vector2 right)
|
||||
{
|
||||
return Mathr.NearEqual(left.X, right.X) && Mathr.NearEqual(left.Y, right.Y);
|
||||
return left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1666,7 +1666,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(Vector2 left, Vector2 right)
|
||||
{
|
||||
return !Mathr.NearEqual(left.X, right.X) || !Mathr.NearEqual(left.Y, right.Y);
|
||||
return !left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1782,7 +1782,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(ref Vector2 other)
|
||||
{
|
||||
return Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y);
|
||||
return X == other.X && Y == other.Y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1790,7 +1790,7 @@ namespace FlaxEngine
|
||||
/// </summary>
|
||||
public static bool Equals(ref Vector2 a, ref Vector2 b)
|
||||
{
|
||||
return Mathr.NearEqual(a.X, b.X) && Mathr.NearEqual(a.Y, b.Y);
|
||||
return a.Equals(ref b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1801,7 +1801,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(Vector2 other)
|
||||
{
|
||||
return Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y);
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1811,7 +1811,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object value)
|
||||
{
|
||||
return value is Vector2 other && Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y);
|
||||
return value is Vector2 other && Equals(ref other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2010,7 +2010,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Vector3 left, Vector3 right)
|
||||
{
|
||||
return Mathr.NearEqual(left.X, right.X) && Mathr.NearEqual(left.Y, right.Y) && Mathr.NearEqual(left.Z, right.Z);
|
||||
return left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2022,7 +2022,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(Vector3 left, Vector3 right)
|
||||
{
|
||||
return !Mathr.NearEqual(left.X, right.X) || !Mathr.NearEqual(left.Y, right.Y) || !Mathr.NearEqual(left.Z, right.Z);
|
||||
return !left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2141,7 +2141,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(ref Vector3 other)
|
||||
{
|
||||
return Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y) && Mathr.NearEqual(other.Z, Z);
|
||||
return X == other.X && Y == other.Y && Z == other.Z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2152,7 +2152,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(Vector3 other)
|
||||
{
|
||||
return Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y) && Mathr.NearEqual(other.Z, Z);
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2162,7 +2162,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object value)
|
||||
{
|
||||
return value is Vector3 other && Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y) && Mathr.NearEqual(other.Z, Z);
|
||||
return value is Vector3 other && Equals(ref other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1362,7 +1362,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Vector4 left, Vector4 right)
|
||||
{
|
||||
return Mathr.NearEqual(left.X, right.X) && Mathr.NearEqual(left.Y, right.Y) && Mathr.NearEqual(left.Z, right.Z) && Mathr.NearEqual(left.W, right.W);
|
||||
return left.Equals(ref right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1493,7 +1493,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public bool Equals(ref Vector4 other)
|
||||
{
|
||||
return Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y) && Mathr.NearEqual(other.Z, Z) && Mathr.NearEqual(other.W, W);
|
||||
return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1504,7 +1504,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(Vector4 other)
|
||||
{
|
||||
return Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y) && Mathr.NearEqual(other.Z, Z) && Mathr.NearEqual(other.W, W);
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1514,7 +1514,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object value)
|
||||
{
|
||||
return value is Vector4 other && Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y) && Mathr.NearEqual(other.Z, Z) && Mathr.NearEqual(other.W, W);
|
||||
return value is Vector4 other && Equals(ref other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
36
Source/Engine/Core/ScopeExit.h
Normal file
36
Source/Engine/Core/ScopeExit.h
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Core.h"
|
||||
|
||||
template<typename FuncType>
|
||||
struct ScopeExit
|
||||
{
|
||||
explicit ScopeExit(FuncType&& func)
|
||||
: _func((FuncType&&)func)
|
||||
{
|
||||
}
|
||||
|
||||
~ScopeExit()
|
||||
{
|
||||
_func();
|
||||
}
|
||||
|
||||
private:
|
||||
FuncType _func;
|
||||
};
|
||||
|
||||
namespace THelpers
|
||||
{
|
||||
struct ScopeExitInternal
|
||||
{
|
||||
template<typename FuncType>
|
||||
ScopeExit<FuncType> operator*(FuncType&& func)
|
||||
{
|
||||
return ScopeExit<FuncType>((FuncType&&)func);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#define SCOPE_EXIT const auto CONCAT_MACROS(__scopeExit, __LINE__) = THelpers::ScopeExitInternal() * [&]()
|
||||
@@ -1162,9 +1162,9 @@ bool Variant::operator==(const Variant& other) const
|
||||
case VariantType::Enum:
|
||||
return AsEnum == other.AsEnum;
|
||||
case VariantType::Float:
|
||||
return Math::NearEqual(AsFloat, other.AsFloat);
|
||||
return AsFloat == other.AsFloat;
|
||||
case VariantType::Double:
|
||||
return Math::Abs(AsDouble - other.AsDouble) < ZeroTolerance;
|
||||
return AsDouble == other.AsDouble;
|
||||
case VariantType::Pointer:
|
||||
return AsPointer == other.AsPointer;
|
||||
case VariantType::String:
|
||||
|
||||
@@ -99,6 +99,7 @@ struct DebugGeometryBuffer
|
||||
{
|
||||
GPUBuffer* Buffer;
|
||||
float TimeLeft;
|
||||
bool Lines;
|
||||
Matrix Transform;
|
||||
};
|
||||
|
||||
@@ -234,6 +235,14 @@ void TeleportList(const Float3& delta, Array<DebugText3D>& list)
|
||||
}
|
||||
}
|
||||
|
||||
void TeleportList(const Float3& delta, Array<DebugGeometryBuffer>& list)
|
||||
{
|
||||
for (auto& v : list)
|
||||
{
|
||||
v.Transform.SetTranslation(v.Transform.GetTranslation() + delta);
|
||||
}
|
||||
}
|
||||
|
||||
struct DebugDrawData
|
||||
{
|
||||
Array<DebugGeometryBuffer> GeometryBuffers;
|
||||
@@ -302,6 +311,7 @@ struct DebugDrawData
|
||||
|
||||
void Teleport(const Float3& delta)
|
||||
{
|
||||
TeleportList(delta, GeometryBuffers);
|
||||
TeleportList(delta, DefaultLines);
|
||||
TeleportList(delta, OneFrameLines);
|
||||
TeleportList(delta, DefaultTriangles);
|
||||
@@ -812,6 +822,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
|
||||
defaultWireTriangles = WriteLists(vertexCounter, Context->DebugDrawDefault.DefaultWireTriangles, Context->DebugDrawDefault.OneFrameWireTriangles);
|
||||
{
|
||||
PROFILE_CPU_NAMED("Flush");
|
||||
ZoneValue(DebugDrawVB->Data.Count() / 1024); // Size in kB
|
||||
DebugDrawVB->Flush(context);
|
||||
}
|
||||
}
|
||||
@@ -871,8 +882,8 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
|
||||
Matrix mvp;
|
||||
Matrix::Multiply(geometry.Transform, vp, mvp);
|
||||
Matrix::Transpose(mvp, tmp.ViewProjection);
|
||||
auto state = data.EnableDepthTest ? (geometry.Lines ? &DebugDrawPsLinesDepthTest : &DebugDrawPsTrianglesDepthTest) : (geometry.Lines ? &DebugDrawPsLinesDefault : &DebugDrawPsTrianglesDefault);
|
||||
context->UpdateCB(cb, &tmp);
|
||||
auto state = data.EnableDepthTest ? &DebugDrawPsLinesDepthTest : &DebugDrawPsLinesDefault;
|
||||
context->SetState(state->Get(enableDepthWrite, true));
|
||||
context->BindVB(ToSpan(&geometry.Buffer, 1));
|
||||
context->Draw(0, geometry.Buffer->GetElementsCount());
|
||||
@@ -920,8 +931,9 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
|
||||
Matrix mvp;
|
||||
Matrix::Multiply(geometry.Transform, vp, mvp);
|
||||
Matrix::Transpose(mvp, tmp.ViewProjection);
|
||||
auto state = geometry.Lines ? &DebugDrawPsLinesDefault : &DebugDrawPsTrianglesDefault;
|
||||
context->UpdateCB(cb, &tmp);
|
||||
context->SetState(DebugDrawPsLinesDefault.Get(false, false));
|
||||
context->SetState(state->Get(false, false));
|
||||
context->BindVB(ToSpan(&geometry.Buffer, 1));
|
||||
context->Draw(0, geometry.Buffer->GetElementsCount());
|
||||
}
|
||||
@@ -1166,6 +1178,7 @@ void DebugDraw::DrawLines(GPUBuffer* lines, const Matrix& transform, float durat
|
||||
auto& geometry = debugDrawData.GeometryBuffers.AddOne();
|
||||
geometry.Buffer = lines;
|
||||
geometry.TimeLeft = duration;
|
||||
geometry.Lines = true;
|
||||
geometry.Transform = transform * Matrix::Translation(-Context->Origin);
|
||||
}
|
||||
|
||||
@@ -1522,6 +1535,23 @@ void DebugDraw::DrawTriangles(const Span<Float3>& vertices, const Matrix& transf
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDraw::DrawTriangles(GPUBuffer* triangles, const Matrix& transform, float duration, bool depthTest)
|
||||
{
|
||||
if (triangles == nullptr || triangles->GetSize() == 0)
|
||||
return;
|
||||
if (triangles->GetSize() % (sizeof(Vertex) * 3) != 0)
|
||||
{
|
||||
DebugLog::ThrowException("Cannot draw debug lines with incorrect amount of items in array");
|
||||
return;
|
||||
}
|
||||
auto& debugDrawData = depthTest ? Context->DebugDrawDepthTest : Context->DebugDrawDefault;
|
||||
auto& geometry = debugDrawData.GeometryBuffers.AddOne();
|
||||
geometry.Buffer = triangles;
|
||||
geometry.TimeLeft = duration;
|
||||
geometry.Lines = false;
|
||||
geometry.Transform = transform * Matrix::Translation(-Context->Origin);
|
||||
}
|
||||
|
||||
void DebugDraw::DrawTriangles(const Array<Float3>& vertices, const Color& color, float duration, bool depthTest)
|
||||
{
|
||||
DrawTriangles(Span<Float3>(vertices.Get(), vertices.Count()), color, duration, depthTest);
|
||||
|
||||
@@ -74,7 +74,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
API_FUNCTION() static bool CanClear(void* context = nullptr);
|
||||
#endif
|
||||
|
||||
// Gets the last view position when rendering the current context. Can be sued for custom culling or LODing when drawing more complex shapes.
|
||||
// Gets the last view position when rendering the current context. Can be used for custom culling or LODing when drawing more complex shapes.
|
||||
static Vector3 GetViewPos();
|
||||
|
||||
/// <summary>
|
||||
@@ -296,12 +296,21 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// Draws the triangles.
|
||||
/// </summary>
|
||||
/// <param name="vertices">The triangle vertices list (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
API_FUNCTION() static void DrawTriangles(const Span<Float3>& vertices, const Matrix& transform, const Color& color = Color::White, float duration = 0.0f, bool depthTest = true);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the triangles using the provided vertex buffer that contains groups of 3 Vertex elements per-triangle.
|
||||
/// </summary>
|
||||
/// <param name="triangles">The GPU buffer with vertices for triangles (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
API_FUNCTION() static void DrawTriangles(GPUBuffer* triangles, const Matrix& transform, float duration = 0.0f, bool depthTest = true);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the triangles.
|
||||
/// </summary>
|
||||
@@ -315,7 +324,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// Draws the triangles.
|
||||
/// </summary>
|
||||
/// <param name="vertices">The triangle vertices list (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
@@ -336,7 +345,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// </summary>
|
||||
/// <param name="vertices">The triangle vertices list.</param>
|
||||
/// <param name="indices">The triangle indices list (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
@@ -357,7 +366,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// </summary>
|
||||
/// <param name="vertices">The triangle vertices list.</param>
|
||||
/// <param name="indices">The triangle indices list (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
@@ -376,7 +385,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// Draws the triangles.
|
||||
/// </summary>
|
||||
/// <param name="vertices">The triangle vertices list (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
@@ -395,7 +404,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// Draws the triangles.
|
||||
/// </summary>
|
||||
/// <param name="vertices">The triangle vertices list (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
@@ -416,7 +425,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// </summary>
|
||||
/// <param name="vertices">The triangle vertices list.</param>
|
||||
/// <param name="indices">The triangle indices list (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
@@ -437,7 +446,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// </summary>
|
||||
/// <param name="vertices">The triangle vertices list.</param>
|
||||
/// <param name="indices">The triangle indices list (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
|
||||
@@ -459,6 +459,15 @@ bool Engine::IsEditor()
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Engine::IsPlayMode()
|
||||
{
|
||||
#if USE_EDITOR
|
||||
return Editor::IsPlayMode;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
int32 Engine::GetFramesPerSecond()
|
||||
{
|
||||
return EngineImpl::Fps;
|
||||
|
||||
@@ -178,6 +178,11 @@ public:
|
||||
/// </summary>
|
||||
API_PROPERTY() static bool IsEditor();
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the editor is in play mode or will always return true in a shipped applications.
|
||||
/// </summary>
|
||||
API_PROPERTY() static bool IsPlayMode();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of frames rendered during last second known as Frames Per Second. User scripts updates or fixed updates for physics may run at a different frequency than scene rendering. Use this property to get an accurate amount of frames rendered during the last second.
|
||||
/// </summary>
|
||||
|
||||
@@ -52,7 +52,7 @@ API_STRUCT(NoPod) struct FLAXENGINE_API FoliageInstance
|
||||
public:
|
||||
bool operator==(const FoliageInstance& v) const
|
||||
{
|
||||
return Type == v.Type && Math::NearEqual(Random, v.Random) && Transform == v.Transform;
|
||||
return Type == v.Type && Random == v.Random && Transform == v.Transform;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -428,6 +428,21 @@ public:
|
||||
/// </summary>
|
||||
Array<AnimationData> Animations;
|
||||
|
||||
public:
|
||||
// See ModelTool::PositionFormat
|
||||
enum class PositionFormats
|
||||
{
|
||||
Float32,
|
||||
Float16,
|
||||
} PositionFormat = PositionFormats::Float32;
|
||||
|
||||
// See ModelTool::TexCoordFormats
|
||||
enum class TexCoordFormats
|
||||
{
|
||||
Float16,
|
||||
UNorm8,
|
||||
} TexCoordFormat = TexCoordFormats::Float16;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Automatically calculates the screen size for every model LOD for a proper transitions.
|
||||
|
||||
@@ -1230,7 +1230,7 @@ void InputService::Update()
|
||||
{
|
||||
for (auto i = Axes.Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
if (Math::NotNearEqual(i->Value.Value, i->Value.PrevValue))
|
||||
if (i->Value.Value != i->Value.PrevValue)
|
||||
{
|
||||
Input::AxisValueChanged(i->Key);
|
||||
}
|
||||
|
||||
@@ -36,8 +36,6 @@
|
||||
#define CHECK_EXECUTE_IN_EDITOR
|
||||
#endif
|
||||
|
||||
#define ACTOR_ORIENTATION_EPSILON 0.000000001f
|
||||
|
||||
// Start loop over actor children/scripts from the beginning to account for any newly added or removed actors.
|
||||
#define ACTOR_LOOP_START_MODIFIED_HIERARCHY() _isHierarchyDirty = false
|
||||
#define ACTOR_LOOP_CHECK_MODIFIED_HIERARCHY() if (_isHierarchyDirty) { _isHierarchyDirty = false; i = -1; }
|
||||
@@ -660,7 +658,7 @@ void Actor::SetStaticFlags(StaticFlags value)
|
||||
void Actor::SetTransform(const Transform& value)
|
||||
{
|
||||
CHECK(!value.IsNanOrInfinity());
|
||||
if (!(Vector3::NearEqual(_transform.Translation, value.Translation) && Quaternion::NearEqual(_transform.Orientation, value.Orientation, ACTOR_ORIENTATION_EPSILON) && Float3::NearEqual(_transform.Scale, value.Scale)))
|
||||
if (_transform.Translation != value.Translation || _transform.Orientation != value.Orientation || _transform.Scale != value.Scale)
|
||||
{
|
||||
if (_parent)
|
||||
_parent->_transform.WorldToLocal(value, _localTransform);
|
||||
@@ -673,7 +671,7 @@ void Actor::SetTransform(const Transform& value)
|
||||
void Actor::SetPosition(const Vector3& value)
|
||||
{
|
||||
CHECK(!value.IsNanOrInfinity());
|
||||
if (!Vector3::NearEqual(_transform.Translation, value))
|
||||
if (_transform.Translation != value)
|
||||
{
|
||||
if (_parent)
|
||||
_localTransform.Translation = _parent->_transform.WorldToLocal(value);
|
||||
@@ -686,7 +684,7 @@ void Actor::SetPosition(const Vector3& value)
|
||||
void Actor::SetOrientation(const Quaternion& value)
|
||||
{
|
||||
CHECK(!value.IsNanOrInfinity());
|
||||
if (!Quaternion::NearEqual(_transform.Orientation, value, ACTOR_ORIENTATION_EPSILON))
|
||||
if (_transform.Orientation != value)
|
||||
{
|
||||
if (_parent)
|
||||
_parent->_transform.WorldToLocal(value, _localTransform.Orientation);
|
||||
@@ -699,7 +697,7 @@ void Actor::SetOrientation(const Quaternion& value)
|
||||
void Actor::SetScale(const Float3& value)
|
||||
{
|
||||
CHECK(!value.IsNanOrInfinity());
|
||||
if (!Float3::NearEqual(_transform.Scale, value))
|
||||
if (_transform.Scale != value)
|
||||
{
|
||||
if (_parent)
|
||||
Float3::Divide(value, _parent->_transform.Scale, _localTransform.Scale);
|
||||
@@ -748,7 +746,7 @@ void Actor::ResetLocalTransform()
|
||||
void Actor::SetLocalTransform(const Transform& value)
|
||||
{
|
||||
CHECK(!value.IsNanOrInfinity());
|
||||
if (!(Vector3::NearEqual(_localTransform.Translation, value.Translation) && Quaternion::NearEqual(_localTransform.Orientation, value.Orientation, ACTOR_ORIENTATION_EPSILON) && Float3::NearEqual(_localTransform.Scale, value.Scale)))
|
||||
if (_localTransform.Translation != value.Translation || _localTransform.Orientation != value.Orientation || _localTransform.Scale != value.Scale)
|
||||
{
|
||||
_localTransform = value;
|
||||
OnTransformChanged();
|
||||
@@ -758,7 +756,7 @@ void Actor::SetLocalTransform(const Transform& value)
|
||||
void Actor::SetLocalPosition(const Vector3& value)
|
||||
{
|
||||
CHECK(!value.IsNanOrInfinity());
|
||||
if (!Vector3::NearEqual(_localTransform.Translation, value))
|
||||
if (_localTransform.Translation != value)
|
||||
{
|
||||
_localTransform.Translation = value;
|
||||
OnTransformChanged();
|
||||
@@ -770,7 +768,7 @@ void Actor::SetLocalOrientation(const Quaternion& value)
|
||||
CHECK(!value.IsNanOrInfinity());
|
||||
Quaternion v = value;
|
||||
v.Normalize();
|
||||
if (!Quaternion::NearEqual(_localTransform.Orientation, v, ACTOR_ORIENTATION_EPSILON))
|
||||
if (_localTransform.Orientation != value)
|
||||
{
|
||||
_localTransform.Orientation = v;
|
||||
OnTransformChanged();
|
||||
@@ -780,7 +778,7 @@ void Actor::SetLocalOrientation(const Quaternion& value)
|
||||
void Actor::SetLocalScale(const Float3& value)
|
||||
{
|
||||
CHECK(!value.IsNanOrInfinity());
|
||||
if (!Float3::NearEqual(_localTransform.Scale, value))
|
||||
if (_localTransform.Scale != value)
|
||||
{
|
||||
_localTransform.Scale = value;
|
||||
OnTransformChanged();
|
||||
|
||||
@@ -65,7 +65,7 @@ void BoxBrush::SetMode(BrushMode value)
|
||||
|
||||
void BoxBrush::SetCenter(const Vector3& value)
|
||||
{
|
||||
if (Vector3::NearEqual(value, _center))
|
||||
if (value == _center)
|
||||
return;
|
||||
|
||||
_center = value;
|
||||
@@ -77,7 +77,7 @@ void BoxBrush::SetCenter(const Vector3& value)
|
||||
|
||||
void BoxBrush::SetSize(const Vector3& value)
|
||||
{
|
||||
if (Vector3::NearEqual(value, _size))
|
||||
if (value == _size)
|
||||
return;
|
||||
|
||||
_size = value;
|
||||
|
||||
@@ -12,7 +12,7 @@ BoxVolume::BoxVolume(const SpawnParams& params)
|
||||
|
||||
void BoxVolume::SetSize(const Vector3& value)
|
||||
{
|
||||
if (!Vector3::NearEqual(value, _size))
|
||||
if (value != _size)
|
||||
{
|
||||
const auto prevBounds = _box;
|
||||
_size = value;
|
||||
|
||||
@@ -70,7 +70,7 @@ float Camera::GetFieldOfView() const
|
||||
void Camera::SetFieldOfView(float value)
|
||||
{
|
||||
value = Math::Clamp(value, 1.0f, 179.9f);
|
||||
if (Math::NotNearEqual(_fov, value))
|
||||
if (_fov != value)
|
||||
{
|
||||
_fov = value;
|
||||
UpdateCache();
|
||||
@@ -85,7 +85,7 @@ float Camera::GetCustomAspectRatio() const
|
||||
void Camera::SetCustomAspectRatio(float value)
|
||||
{
|
||||
value = Math::Clamp(value, 0.0f, 100.0f);
|
||||
if (Math::NotNearEqual(_customAspectRatio, value))
|
||||
if (_customAspectRatio != value)
|
||||
{
|
||||
_customAspectRatio = value;
|
||||
UpdateCache();
|
||||
@@ -100,7 +100,7 @@ float Camera::GetNearPlane() const
|
||||
void Camera::SetNearPlane(float value)
|
||||
{
|
||||
value = Math::Clamp(value, 0.001f, _far - 1.0f);
|
||||
if (Math::NotNearEqual(_near, value))
|
||||
if (_near != value)
|
||||
{
|
||||
_near = value;
|
||||
UpdateCache();
|
||||
@@ -115,7 +115,7 @@ float Camera::GetFarPlane() const
|
||||
void Camera::SetFarPlane(float value)
|
||||
{
|
||||
value = Math::Max(value, _near + 1.0f);
|
||||
if (Math::NotNearEqual(_far, value))
|
||||
if (_far != value)
|
||||
{
|
||||
_far = value;
|
||||
UpdateCache();
|
||||
@@ -130,7 +130,7 @@ float Camera::GetOrthographicSize() const
|
||||
void Camera::SetOrthographicSize(float value)
|
||||
{
|
||||
value = Math::Clamp(value, 0.0f, 1000000.0f);
|
||||
if (Math::NotNearEqual(_orthoSize, value))
|
||||
if (_orthoSize != value)
|
||||
{
|
||||
_orthoSize = value;
|
||||
UpdateCache();
|
||||
@@ -145,7 +145,7 @@ float Camera::GetOrthographicScale() const
|
||||
void Camera::SetOrthographicScale(float value)
|
||||
{
|
||||
value = Math::Clamp(value, 0.0001f, 1000000.0f);
|
||||
if (Math::NotNearEqual(_orthoScale, value))
|
||||
if (_orthoScale != value)
|
||||
{
|
||||
_orthoScale = value;
|
||||
UpdateCache();
|
||||
|
||||
@@ -41,7 +41,7 @@ float EnvironmentProbe::GetRadius() const
|
||||
void EnvironmentProbe::SetRadius(float value)
|
||||
{
|
||||
value = Math::Max(0.0f, value);
|
||||
if (Math::NearEqual(value, _radius))
|
||||
if (value == _radius)
|
||||
return;
|
||||
|
||||
_radius = value;
|
||||
|
||||
@@ -49,7 +49,7 @@ float PointLight::GetScaledRadius() const
|
||||
void PointLight::SetRadius(float value)
|
||||
{
|
||||
value = Math::Max(0.0f, value);
|
||||
if (Math::NearEqual(value, _radius))
|
||||
if (value == _radius)
|
||||
return;
|
||||
|
||||
_radius = value;
|
||||
|
||||
@@ -26,7 +26,7 @@ SkyLight::SkyLight(const SpawnParams& params)
|
||||
void SkyLight::SetRadius(float value)
|
||||
{
|
||||
value = Math::Max(0.0f, value);
|
||||
if (Math::NearEqual(value, _radius))
|
||||
if (value == _radius)
|
||||
return;
|
||||
|
||||
_radius = value;
|
||||
|
||||
@@ -59,7 +59,7 @@ float SplineModel::GetQuality() const
|
||||
void SplineModel::SetQuality(float value)
|
||||
{
|
||||
value = Math::Clamp(value, 0.0f, 100.0f);
|
||||
if (Math::NearEqual(value, _quality))
|
||||
if (value == _quality)
|
||||
return;
|
||||
_quality = value;
|
||||
OnSplineUpdated();
|
||||
@@ -72,7 +72,7 @@ float SplineModel::GetBoundsScale() const
|
||||
|
||||
void SplineModel::SetBoundsScale(float value)
|
||||
{
|
||||
if (Math::NearEqual(_boundsScale, value))
|
||||
if (_boundsScale == value)
|
||||
return;
|
||||
_boundsScale = value;
|
||||
OnSplineUpdated();
|
||||
|
||||
@@ -57,7 +57,7 @@ float SpotLight::GetScaledRadius() const
|
||||
void SpotLight::SetRadius(float value)
|
||||
{
|
||||
value = Math::Max(0.0f, value);
|
||||
if (Math::NearEqual(value, _radius))
|
||||
if (value == _radius)
|
||||
return;
|
||||
|
||||
_radius = value;
|
||||
@@ -70,7 +70,7 @@ void SpotLight::SetOuterConeAngle(float value)
|
||||
value = Math::Clamp(value, 0.0f, 89.0f);
|
||||
|
||||
// Check if value will change
|
||||
if (!Math::NearEqual(value, _outerConeAngle))
|
||||
if (value != _outerConeAngle)
|
||||
{
|
||||
// Change values
|
||||
_innerConeAngle = Math::Min(_innerConeAngle, value - ZeroTolerance);
|
||||
@@ -86,7 +86,7 @@ void SpotLight::SetInnerConeAngle(float value)
|
||||
value = Math::Clamp(value, 0.0f, 89.0f);
|
||||
|
||||
// Check if value will change
|
||||
if (!Math::NearEqual(value, _innerConeAngle))
|
||||
if (value != _innerConeAngle)
|
||||
{
|
||||
// Change values
|
||||
_innerConeAngle = value;
|
||||
|
||||
@@ -60,7 +60,7 @@ float StaticModel::GetBoundsScale() const
|
||||
|
||||
void StaticModel::SetBoundsScale(float value)
|
||||
{
|
||||
if (Math::NearEqual(_boundsScale, value))
|
||||
if (_boundsScale == value)
|
||||
return;
|
||||
|
||||
_boundsScale = value;
|
||||
|
||||
22
Source/Engine/Level/MeshReference.cs
Normal file
22
Source/Engine/Level/MeshReference.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
|
||||
using FlaxEngine.Json;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
partial class ModelInstanceActor
|
||||
{
|
||||
partial struct MeshReference : ICustomValueEquals
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public bool ValueEquals(object other)
|
||||
{
|
||||
var o = (MeshReference)other;
|
||||
return JsonSerializer.ValueEquals(Actor, o.Actor) &&
|
||||
LODIndex == o.LODIndex &&
|
||||
MeshIndex == o.MeshIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1090,7 +1090,7 @@ bool Prefab::ApplyAllInternal(Actor* targetActor, bool linkTargetActorObjectToPr
|
||||
root = dynamic_cast<Actor*>(sceneObjects.Value->At(targetActorIdx));
|
||||
}
|
||||
|
||||
// Try using the first actor without a parent as a new ro0t
|
||||
// Try using the first actor without a parent as a new root
|
||||
for (int32 i = 1; i < sceneObjects->Count(); i++)
|
||||
{
|
||||
SceneObject* obj = sceneObjects.Value->At(i);
|
||||
|
||||
@@ -293,7 +293,7 @@ void NavMeshRuntime::SetTileSize(float tileSize)
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
// Skip if the same or invalid
|
||||
if (Math::NearEqual(_tileSize, tileSize) || tileSize < 1)
|
||||
if (_tileSize == tileSize || tileSize < 1)
|
||||
return;
|
||||
|
||||
// Dispose the existing mesh (its invalid)
|
||||
|
||||
@@ -109,7 +109,7 @@ Color NavMeshRuntime::NavAreasColors[64];
|
||||
|
||||
bool NavAgentProperties::operator==(const NavAgentProperties& other) const
|
||||
{
|
||||
return Math::NearEqual(Radius, other.Radius) && Math::NearEqual(Height, other.Height) && Math::NearEqual(StepHeight, other.StepHeight) && Math::NearEqual(MaxSlopeAngle, other.MaxSlopeAngle) && Math::NearEqual(MaxSpeed, other.MaxSpeed) && Math::NearEqual(CrowdSeparationWeight, other.CrowdSeparationWeight);
|
||||
return Radius == other.Radius && Height == other.Height && StepHeight == other.StepHeight && MaxSlopeAngle == other.MaxSlopeAngle && MaxSpeed == other.MaxSpeed && CrowdSeparationWeight == other.CrowdSeparationWeight;
|
||||
}
|
||||
|
||||
bool NavAgentMask::IsAgentSupported(int32 agentIndex) const
|
||||
@@ -150,12 +150,12 @@ bool NavAgentMask::operator==(const NavAgentMask& other) const
|
||||
|
||||
bool NavAreaProperties::operator==(const NavAreaProperties& other) const
|
||||
{
|
||||
return Name == other.Name && Id == other.Id && Math::NearEqual(Cost, other.Cost);
|
||||
return Name == other.Name && Id == other.Id && Cost == other.Cost;
|
||||
}
|
||||
|
||||
bool NavMeshProperties::operator==(const NavMeshProperties& other) const
|
||||
{
|
||||
return Name == other.Name && Quaternion::NearEqual(Rotation, other.Rotation, 0.001f) && Agent == other.Agent && Vector3::NearEqual(DefaultQueryExtent, other.DefaultQueryExtent);
|
||||
return Name == other.Name && Rotation == other.Rotation && Agent == other.Agent && DefaultQueryExtent == other.DefaultQueryExtent;
|
||||
}
|
||||
|
||||
class NavigationService : public EngineService
|
||||
|
||||
@@ -223,7 +223,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
ASSERT(!isnan(sphere.Radius) && !isinf(sphere.Radius) && !sphere.Center.IsNanOrInfinity());
|
||||
CHECK_RETURN(!isnan(sphere.Radius) && !isinf(sphere.Radius) && !sphere.Center.IsNanOrInfinity(), false);
|
||||
|
||||
// Expand sphere based on the render modules rules (sprite or mesh size)
|
||||
for (int32 moduleIndex = 0; moduleIndex < emitter->Graph.RenderModules.Count(); moduleIndex++)
|
||||
@@ -244,7 +244,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa
|
||||
Vector2::Max(*((Vector2*)spriteSize), maxSpriteSize, maxSpriteSize);
|
||||
spriteSize += stride;
|
||||
}
|
||||
ASSERT(!maxSpriteSize.IsNanOrInfinity());
|
||||
CHECK_RETURN(!maxSpriteSize.IsNanOrInfinity(), false);
|
||||
|
||||
// Enlarge the emitter bounds sphere
|
||||
sphere.Radius += maxSpriteSize.MaxValue();
|
||||
@@ -267,7 +267,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa
|
||||
if (radius > maxRadius)
|
||||
maxRadius = radius;
|
||||
}
|
||||
ASSERT(!isnan(maxRadius) && !isinf(maxRadius));
|
||||
CHECK_RETURN(!isnan(maxRadius) && !isinf(maxRadius), false);
|
||||
|
||||
// Enlarge the emitter bounds sphere
|
||||
sphere.Radius += maxRadius;
|
||||
@@ -315,7 +315,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa
|
||||
maxRibbonWidth = Math::Max(*((float*)ribbonWidth), maxRibbonWidth);
|
||||
ribbonWidth += stride;
|
||||
}
|
||||
ASSERT(!isnan(maxRibbonWidth) && !isinf(maxRibbonWidth));
|
||||
CHECK_RETURN(!isnan(maxRibbonWidth) && !isinf(maxRibbonWidth), false);
|
||||
|
||||
// Enlarge the emitter bounds sphere
|
||||
sphere.Radius += maxRibbonWidth * 0.5f;
|
||||
@@ -335,7 +335,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa
|
||||
maxRadius = Math::Max(*((float*)radius), maxRadius);
|
||||
radius += stride;
|
||||
}
|
||||
ASSERT(!isnan(maxRadius) && !isinf(maxRadius));
|
||||
CHECK_RETURN(!isnan(maxRadius) && !isinf(maxRadius), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -340,6 +340,7 @@ void Cloth::DrawPhysicsDebug(RenderView& view)
|
||||
#if WITH_CLOTH && COMPILE_WITH_DEBUG_DRAW
|
||||
if (_cloth)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
const ModelInstanceActor::MeshReference mesh = GetMesh();
|
||||
if (mesh.Actor == nullptr)
|
||||
return;
|
||||
|
||||
@@ -44,7 +44,7 @@ void RigidBody::SetIsKinematic(const bool value)
|
||||
|
||||
void RigidBody::SetLinearDamping(float value)
|
||||
{
|
||||
if (Math::NearEqual(value, _linearDamping))
|
||||
if (value == _linearDamping)
|
||||
return;
|
||||
_linearDamping = value;
|
||||
if (_actor)
|
||||
@@ -53,7 +53,7 @@ void RigidBody::SetLinearDamping(float value)
|
||||
|
||||
void RigidBody::SetAngularDamping(float value)
|
||||
{
|
||||
if (Math::NearEqual(value, _angularDamping))
|
||||
if (value == _angularDamping)
|
||||
return;
|
||||
_angularDamping = value;
|
||||
if (_actor)
|
||||
@@ -108,7 +108,7 @@ void RigidBody::SetUpdateMassWhenScaleChanges(bool value)
|
||||
|
||||
void RigidBody::SetMaxAngularVelocity(float value)
|
||||
{
|
||||
if (Math::NearEqual(value, _maxAngularVelocity))
|
||||
if (value == _maxAngularVelocity)
|
||||
return;
|
||||
_maxAngularVelocity = value;
|
||||
if (_actor)
|
||||
@@ -135,7 +135,7 @@ float RigidBody::GetMass() const
|
||||
|
||||
void RigidBody::SetMass(float value)
|
||||
{
|
||||
if (Math::NearEqual(value, _mass))
|
||||
if (value == _mass)
|
||||
return;
|
||||
_mass = value;
|
||||
_overrideMass = true;
|
||||
@@ -149,7 +149,7 @@ float RigidBody::GetMassScale() const
|
||||
|
||||
void RigidBody::SetMassScale(float value)
|
||||
{
|
||||
if (Math::NearEqual(value, _massScale))
|
||||
if (value == _massScale)
|
||||
return;
|
||||
_massScale = value;
|
||||
UpdateMass();
|
||||
@@ -157,7 +157,7 @@ void RigidBody::SetMassScale(float value)
|
||||
|
||||
void RigidBody::SetCenterOfMassOffset(const Float3& value)
|
||||
{
|
||||
if (Float3::NearEqual(value, _centerOfMassOffset))
|
||||
if (value == _centerOfMassOffset)
|
||||
return;
|
||||
_centerOfMassOffset = value;
|
||||
if (_actor)
|
||||
@@ -380,7 +380,7 @@ void RigidBody::UpdateBounds()
|
||||
void RigidBody::UpdateScale()
|
||||
{
|
||||
const Float3 scale = GetScale();
|
||||
if (Float3::NearEqual(_cachedScale, scale))
|
||||
if (_cachedScale == scale)
|
||||
return;
|
||||
_cachedScale = scale;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ BoxCollider::BoxCollider(const SpawnParams& params)
|
||||
|
||||
void BoxCollider::SetSize(const Float3& value)
|
||||
{
|
||||
if (Float3::NearEqual(value, _size))
|
||||
if (value == _size)
|
||||
return;
|
||||
_size = value;
|
||||
|
||||
@@ -162,7 +162,7 @@ void BoxCollider::UpdateBounds()
|
||||
|
||||
void BoxCollider::GetGeometry(CollisionShape& collision)
|
||||
{
|
||||
Float3 size = _size * _cachedScale;
|
||||
Float3 size = _size * _transform.Scale;
|
||||
const float minSize = 0.001f;
|
||||
size = Float3::Max(size.GetAbsolute() * 0.5f, Float3(minSize));
|
||||
collision.SetBox(size.Raw);
|
||||
|
||||
@@ -11,7 +11,7 @@ CapsuleCollider::CapsuleCollider(const SpawnParams& params)
|
||||
|
||||
void CapsuleCollider::SetRadius(const float value)
|
||||
{
|
||||
if (Math::NearEqual(value, _radius))
|
||||
if (value == _radius)
|
||||
return;
|
||||
|
||||
_radius = value;
|
||||
@@ -22,7 +22,7 @@ void CapsuleCollider::SetRadius(const float value)
|
||||
|
||||
void CapsuleCollider::SetHeight(const float value)
|
||||
{
|
||||
if (Math::NearEqual(value, _height))
|
||||
if (value == _height)
|
||||
return;
|
||||
|
||||
_height = value;
|
||||
@@ -43,10 +43,9 @@ void CapsuleCollider::DrawPhysicsDebug(RenderView& view)
|
||||
return;
|
||||
Quaternion rotation;
|
||||
Quaternion::Multiply(_transform.Orientation, Quaternion::Euler(0, 90, 0), rotation);
|
||||
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||
const float minSize = 0.001f;
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling, minSize);
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
|
||||
const float radius = Math::Max(Math::Abs(_radius) * _cachedScale, minSize);
|
||||
const float height = Math::Max(Math::Abs(_height) * _cachedScale, minSize);
|
||||
if (view.Mode == ViewMode::PhysicsColliders && !GetIsTrigger())
|
||||
DEBUG_DRAW_CAPSULE(_transform.LocalToWorld(_center), rotation, radius, height, _staticActor ? Color::CornflowerBlue : Color::Orchid, 0, true);
|
||||
else
|
||||
@@ -57,10 +56,9 @@ void CapsuleCollider::OnDebugDrawSelected()
|
||||
{
|
||||
Quaternion rotation;
|
||||
Quaternion::Multiply(_transform.Orientation, Quaternion::Euler(0, 90, 0), rotation);
|
||||
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||
const float minSize = 0.001f;
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling, minSize);
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
|
||||
const float radius = Math::Max(Math::Abs(_radius) * _cachedScale, minSize);
|
||||
const float height = Math::Max(Math::Abs(_height) * _cachedScale, minSize);
|
||||
const Vector3 position = _transform.LocalToWorld(_center);
|
||||
DEBUG_DRAW_WIRE_CAPSULE(position, rotation, radius, height, Color::GreenYellow, 0, false);
|
||||
|
||||
@@ -92,9 +90,8 @@ void CapsuleCollider::UpdateBounds()
|
||||
|
||||
void CapsuleCollider::GetGeometry(CollisionShape& collision)
|
||||
{
|
||||
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||
const float minSize = 0.001f;
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling, minSize);
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
|
||||
const float radius = Math::Max(Math::Abs(_radius) * _cachedScale, minSize);
|
||||
const float height = Math::Max(Math::Abs(_height) * _cachedScale, minSize);
|
||||
collision.SetCapsule(radius, height * 0.5f);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ CharacterController::CharacterController(const SpawnParams& params)
|
||||
, _upDirection(Vector3::Up)
|
||||
, _gravityDisplacement(Vector3::Zero)
|
||||
, _nonWalkableMode(NonWalkableModes::PreventClimbing)
|
||||
, _originMode(OriginModes::CapsuleCenter)
|
||||
, _lastFlags(CollisionFlags::None)
|
||||
{
|
||||
_contactOffset = 10.0f;
|
||||
@@ -33,11 +34,9 @@ float CharacterController::GetRadius() const
|
||||
|
||||
void CharacterController::SetRadius(const float value)
|
||||
{
|
||||
if (Math::NearEqual(value, _radius))
|
||||
if (value == _radius)
|
||||
return;
|
||||
|
||||
_radius = value;
|
||||
|
||||
UpdateSize();
|
||||
UpdateBounds();
|
||||
}
|
||||
@@ -49,11 +48,9 @@ float CharacterController::GetHeight() const
|
||||
|
||||
void CharacterController::SetHeight(const float value)
|
||||
{
|
||||
if (Math::NearEqual(value, _height))
|
||||
if (value == _height)
|
||||
return;
|
||||
|
||||
_height = value;
|
||||
|
||||
UpdateSize();
|
||||
UpdateBounds();
|
||||
}
|
||||
@@ -66,7 +63,7 @@ float CharacterController::GetSlopeLimit() const
|
||||
void CharacterController::SetSlopeLimit(float value)
|
||||
{
|
||||
value = Math::Clamp(value, 0.0f, 89.0f);
|
||||
if (Math::NearEqual(value, _slopeLimit))
|
||||
if (value == _slopeLimit)
|
||||
return;
|
||||
_slopeLimit = value;
|
||||
if (_controller)
|
||||
@@ -87,6 +84,23 @@ void CharacterController::SetNonWalkableMode(NonWalkableModes value)
|
||||
PhysicsBackend::SetControllerNonWalkableMode(_controller, (int32)value);
|
||||
}
|
||||
|
||||
CharacterController::OriginModes CharacterController::GetOriginMode() const
|
||||
{
|
||||
return _originMode;
|
||||
}
|
||||
|
||||
void CharacterController::SetOriginMode(OriginModes value)
|
||||
{
|
||||
if (_originMode == value)
|
||||
return;
|
||||
_originMode = value;
|
||||
if (_controller)
|
||||
{
|
||||
DeleteController();
|
||||
CreateController();
|
||||
}
|
||||
}
|
||||
|
||||
float CharacterController::GetStepOffset() const
|
||||
{
|
||||
return _stepOffset;
|
||||
@@ -94,17 +108,13 @@ float CharacterController::GetStepOffset() const
|
||||
|
||||
void CharacterController::SetStepOffset(float value)
|
||||
{
|
||||
if (Math::NearEqual(value, _stepOffset))
|
||||
if (value == _stepOffset)
|
||||
return;
|
||||
|
||||
_stepOffset = value;
|
||||
|
||||
if (_controller)
|
||||
{
|
||||
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||
const float contactOffset = Math::Max(_contactOffset, ZeroTolerance);
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, CC_MIN_SIZE);
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling - contactOffset, CC_MIN_SIZE);
|
||||
float height, radius;
|
||||
GetControllerSize(height, radius);
|
||||
PhysicsBackend::SetControllerStepOffset(_controller, Math::Min(value, height + radius * 2.0f - CC_MIN_SIZE));
|
||||
}
|
||||
}
|
||||
@@ -169,17 +179,69 @@ CharacterController::CollisionFlags CharacterController::SimpleMove(const Vector
|
||||
CharacterController::CollisionFlags CharacterController::Move(const Vector3& displacement)
|
||||
{
|
||||
CollisionFlags result = CollisionFlags::None;
|
||||
if (_controller)
|
||||
if (_controller && !_isUpdatingTransform)
|
||||
{
|
||||
// Perform move
|
||||
const float deltaTime = Time::GetCurrentSafe()->DeltaTime.GetTotalSeconds();
|
||||
result = (CollisionFlags)PhysicsBackend::MoveController(_controller, _shape, displacement, _minMoveDistance, deltaTime);
|
||||
_lastFlags = result;
|
||||
Vector3 position = PhysicsBackend::GetControllerPosition(_controller) - _center;
|
||||
|
||||
// Update position
|
||||
Vector3 position;
|
||||
if (_originMode == OriginModes::Base)
|
||||
position = PhysicsBackend::GetControllerBasePosition(_controller);
|
||||
else
|
||||
position = PhysicsBackend::GetControllerPosition(_controller);
|
||||
position -= _center;
|
||||
_isUpdatingTransform = true;
|
||||
SetPosition(position);
|
||||
_isUpdatingTransform = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void CharacterController::Resize(float height, float radius)
|
||||
{
|
||||
const float heightDiff = height - _height;
|
||||
const float radiusDiff = radius - _radius;
|
||||
if (Math::IsZero(heightDiff) && Math::IsZero(radiusDiff))
|
||||
return;
|
||||
_height = height;
|
||||
_radius = radius;
|
||||
if (_controller)
|
||||
{
|
||||
float centerDiff = heightDiff * 0.5f + radiusDiff;
|
||||
|
||||
// Change physics size
|
||||
GetControllerSize(height, radius);
|
||||
PhysicsBackend::SetControllerSize(_controller, radius, height);
|
||||
Vector3 positionDelta = _upDirection * centerDiff;
|
||||
|
||||
// Change physics position to maintain feet placement (base)
|
||||
Vector3 position;
|
||||
switch (_originMode)
|
||||
{
|
||||
case OriginModes::CapsuleCenter:
|
||||
position = PhysicsBackend::GetControllerPosition(_controller);
|
||||
position += positionDelta;
|
||||
_center += positionDelta;
|
||||
PhysicsBackend::SetControllerPosition(_controller, position);
|
||||
break;
|
||||
case OriginModes::Base:
|
||||
position = PhysicsBackend::GetControllerBasePosition(_controller);
|
||||
position += positionDelta;
|
||||
PhysicsBackend::SetControllerBasePosition(_controller, position);
|
||||
break;
|
||||
}
|
||||
|
||||
// Change actor position
|
||||
_isUpdatingTransform = true;
|
||||
SetPosition(position - _center);
|
||||
_isUpdatingTransform = false;
|
||||
}
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "Engine/Debug/DebugDraw.h"
|
||||
@@ -187,23 +249,47 @@ CharacterController::CollisionFlags CharacterController::Move(const Vector3& dis
|
||||
|
||||
void CharacterController::DrawPhysicsDebug(RenderView& view)
|
||||
{
|
||||
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling, CC_MIN_SIZE);
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, CC_MIN_SIZE);
|
||||
const Vector3 position = _transform.LocalToWorld(_center);
|
||||
Quaternion rotation = Quaternion::Euler(90, 0, 0);
|
||||
const Vector3 position = GetControllerPosition();
|
||||
if (view.Mode == ViewMode::PhysicsColliders)
|
||||
DEBUG_DRAW_CAPSULE(position, Quaternion::Euler(90, 0, 0), radius, height, Color::LightYellow, 0, true);
|
||||
DEBUG_DRAW_CAPSULE(position, rotation, _radius, _height, Color::LightYellow, 0, true);
|
||||
else
|
||||
DEBUG_DRAW_WIRE_CAPSULE(position, Quaternion::Euler(90, 0, 0), radius, height, Color::GreenYellow * 0.8f, 0, true);
|
||||
DEBUG_DRAW_WIRE_CAPSULE(position, rotation, _radius, _height, Color::GreenYellow * 0.8f, 0, true);
|
||||
}
|
||||
|
||||
void CharacterController::OnDebugDrawSelected()
|
||||
{
|
||||
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling, CC_MIN_SIZE);
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, CC_MIN_SIZE);
|
||||
const Vector3 position = _transform.LocalToWorld(_center);
|
||||
DEBUG_DRAW_WIRE_CAPSULE(position, Quaternion::Euler(90, 0, 0), radius, height, Color::GreenYellow, 0, false);
|
||||
Quaternion rotation = Quaternion::Euler(90, 0, 0);
|
||||
const Vector3 position = GetControllerPosition();
|
||||
DEBUG_DRAW_WIRE_CAPSULE(position, rotation, _radius, _height, Color::GreenYellow, 0, false);
|
||||
if (_contactOffset > 0)
|
||||
DEBUG_DRAW_WIRE_CAPSULE(position, rotation, _radius - _contactOffset, _height, Color::Blue.AlphaMultiplied(0.4f), 0, false);
|
||||
#if 1
|
||||
// More technical visuals debugging
|
||||
if (_controller)
|
||||
{
|
||||
float height, radius;
|
||||
GetControllerSize(height, radius);
|
||||
Vector3 base = PhysicsBackend::GetControllerBasePosition(_controller);
|
||||
Vector3 pos = PhysicsBackend::GetControllerPosition(_controller);
|
||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(base, 5.0f), Color::Red, 0, false);
|
||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos, 4.0f), Color::Red, 0, false);
|
||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos + Vector3(0, height * 0.5f, 0), 2.0f), Color::Red, 0, false);
|
||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos - Vector3(0, height * 0.5f, 0), 2.0f), Color::Red, 0, false);
|
||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos + Vector3(0, height * 0.5f, 0), radius), Color::Red.AlphaMultiplied(0.5f), 0, false);
|
||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos - Vector3(0, height * 0.5f, 0), radius), Color::Red.AlphaMultiplied(0.5f), 0, false);
|
||||
DEBUG_DRAW_WIRE_CYLINDER(pos, Quaternion::Identity, radius, height, Color::Red.AlphaMultiplied(0.2f), 0, false);
|
||||
}
|
||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(position, 3.0f), Color::GreenYellow, 0, false);
|
||||
#else
|
||||
if (_controller)
|
||||
{
|
||||
// Physics backend capsule shape
|
||||
float height, radius;
|
||||
GetControllerSize(height, radius);
|
||||
DEBUG_DRAW_WIRE_CAPSULE(PhysicsBackend::GetControllerPosition(_controller), rotation, radius, height, Color::Blue.AlphaMultiplied(0.2f), 0, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Base
|
||||
Collider::OnDebugDrawSelected();
|
||||
@@ -215,10 +301,14 @@ void CharacterController::CreateController()
|
||||
{
|
||||
// Create controller
|
||||
ASSERT(_controller == nullptr && _shape == nullptr);
|
||||
_cachedScale = GetScale();
|
||||
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||
const Vector3 position = _transform.LocalToWorld(_center);
|
||||
_controller = PhysicsBackend::CreateController(GetPhysicsScene()->GetPhysicsScene(), this, this, _contactOffset, position, _slopeLimit, (int32)_nonWalkableMode, Material, Math::Abs(_radius) * scaling, Math::Abs(_height) * scaling, _stepOffset, _shape);
|
||||
_cachedScale = GetScale().GetAbsolute().MaxValue();
|
||||
float height, radius;
|
||||
GetControllerSize(height, radius);
|
||||
Vector3 position = _center;
|
||||
if (_originMode == OriginModes::Base)
|
||||
position += _upDirection * (_height * 0.5f + _radius);
|
||||
position = _transform.LocalToWorld(position);
|
||||
_controller = PhysicsBackend::CreateController(GetPhysicsScene()->GetPhysicsScene(), this, this, _contactOffset, position, _slopeLimit, (int32)_nonWalkableMode, Material, radius, height, _stepOffset, _shape);
|
||||
|
||||
// Setup
|
||||
PhysicsBackend::SetControllerUpDirection(_controller, _upDirection);
|
||||
@@ -241,13 +331,35 @@ void CharacterController::UpdateSize() const
|
||||
{
|
||||
if (_controller)
|
||||
{
|
||||
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling - Math::Max(_contactOffset, ZeroTolerance), CC_MIN_SIZE);
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, CC_MIN_SIZE);
|
||||
float height, radius;
|
||||
GetControllerSize(height, radius);
|
||||
PhysicsBackend::SetControllerSize(_controller, radius, height);
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 CharacterController::GetControllerPosition() const
|
||||
{
|
||||
Vector3 position = _center;
|
||||
if (_originMode == OriginModes::Base)
|
||||
position += _upDirection * (_height * 0.5f + _radius);
|
||||
position = _transform.LocalToWorld(position);
|
||||
return position;
|
||||
}
|
||||
|
||||
void CharacterController::GetControllerSize(float& height, float& radius) const
|
||||
{
|
||||
// Use absolute values including scale
|
||||
height = Math::Abs(_height) * _cachedScale;
|
||||
radius = Math::Abs(_radius) * _cachedScale;
|
||||
|
||||
// Exclude contact offset around the capsule (otherwise character floats in the air)
|
||||
radius = radius - Math::Max(_contactOffset, 0.0f);
|
||||
|
||||
// Prevent too small controllers
|
||||
height = Math::Max(height, CC_MIN_SIZE);
|
||||
radius = Math::Max(radius, CC_MIN_SIZE);
|
||||
}
|
||||
|
||||
void CharacterController::CreateShape()
|
||||
{
|
||||
// Not used
|
||||
@@ -255,10 +367,10 @@ void CharacterController::CreateShape()
|
||||
|
||||
void CharacterController::UpdateBounds()
|
||||
{
|
||||
const float scaling = GetScale().GetAbsolute().MaxValue();
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling, CC_MIN_SIZE);
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, CC_MIN_SIZE);
|
||||
const Vector3 position = _transform.LocalToWorld(_center);
|
||||
_cachedScale = GetScale().GetAbsolute().MaxValue();
|
||||
float height, radius;
|
||||
GetControllerSize(height, radius);
|
||||
const Vector3 position = GetControllerPosition();
|
||||
const Vector3 extent(radius, height * 0.5f + radius, radius);
|
||||
_box = BoundingBox(position - extent, position + extent);
|
||||
BoundingSphere::FromBox(_box, _sphere);
|
||||
@@ -292,6 +404,21 @@ RigidBody* CharacterController::GetAttachedRigidBody() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CharacterController::SetCenter(const Vector3& value)
|
||||
{
|
||||
if (value == _center)
|
||||
return;
|
||||
Vector3 delta = value - _center;
|
||||
_center = value;
|
||||
if (_controller)
|
||||
{
|
||||
// Change physics position while maintaining actor placement
|
||||
Vector3 position = PhysicsBackend::GetControllerPosition(_controller);
|
||||
position += _upDirection * delta;
|
||||
PhysicsBackend::SetControllerPosition(_controller, position);
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterController::OnActiveTransformChanged()
|
||||
{
|
||||
if (!_shape)
|
||||
@@ -300,7 +427,12 @@ void CharacterController::OnActiveTransformChanged()
|
||||
// Change actor transform (but with locking)
|
||||
ASSERT(!_isUpdatingTransform);
|
||||
_isUpdatingTransform = true;
|
||||
const Vector3 position = PhysicsBackend::GetControllerPosition(_controller) - _center;
|
||||
Vector3 position;
|
||||
if (_originMode == OriginModes::Base)
|
||||
position = PhysicsBackend::GetControllerBasePosition(_controller);
|
||||
else
|
||||
position = PhysicsBackend::GetControllerPosition(_controller);
|
||||
position -= _center;
|
||||
SetPosition(position);
|
||||
_isUpdatingTransform = false;
|
||||
|
||||
@@ -319,7 +451,7 @@ void CharacterController::UpdateGeometry()
|
||||
return;
|
||||
|
||||
// Setup shape geometry
|
||||
_cachedScale = GetScale();
|
||||
_cachedScale = GetScale().GetAbsolute().MaxValue();
|
||||
UpdateSize();
|
||||
}
|
||||
|
||||
@@ -382,9 +514,12 @@ void CharacterController::OnTransformChanged()
|
||||
const Vector3 position = _transform.LocalToWorld(_center);
|
||||
if (!_isUpdatingTransform && _controller)
|
||||
{
|
||||
PhysicsBackend::SetControllerPosition(_controller, position);
|
||||
const Float3 scale = GetScale();
|
||||
if (!Float3::NearEqual(_cachedScale, scale))
|
||||
if (_originMode == OriginModes::Base)
|
||||
PhysicsBackend::SetControllerBasePosition(_controller, position);
|
||||
else
|
||||
PhysicsBackend::SetControllerPosition(_controller, position);
|
||||
const float scale = GetScale().GetAbsolute().MaxValue();
|
||||
if (_cachedScale != scale)
|
||||
UpdateGeometry();
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
@@ -41,6 +41,22 @@ public:
|
||||
Below = 1 << 2,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Specifies how a character controller capsule placement.
|
||||
/// </summary>
|
||||
API_ENUM() enum class OriginModes
|
||||
{
|
||||
/// <summary>
|
||||
/// Character origin starts at capsule center (including Center offset properly).
|
||||
/// </summary>
|
||||
CapsuleCenter,
|
||||
|
||||
/// <summary>
|
||||
/// Character origin starts at capsule base position aka character feet placement.
|
||||
/// </summary>
|
||||
Base,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Specifies how a character controller interacts with non-walkable parts.
|
||||
/// </summary>
|
||||
@@ -69,6 +85,7 @@ private:
|
||||
Vector3 _upDirection;
|
||||
Vector3 _gravityDisplacement;
|
||||
NonWalkableModes _nonWalkableMode;
|
||||
OriginModes _originMode;
|
||||
CollisionFlags _lastFlags;
|
||||
|
||||
public:
|
||||
@@ -84,13 +101,13 @@ public:
|
||||
API_PROPERTY() void SetRadius(float value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the height of the capsule, measured in the object's local space. The capsule height will be scaled by the actor's world scale.
|
||||
/// Gets the height of the capsule as a distance between the two sphere centers at the end of the capsule. The capsule height is measured in the object's local space and will be scaled by the actor's world scale.
|
||||
/// </summary>
|
||||
API_PROPERTY(Attributes="EditorOrder(110), DefaultValue(150.0f), EditorDisplay(\"Collider\"), ValueCategory(Utils.ValueCategory.Distance)")
|
||||
float GetHeight() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the height of the capsule, measured in the object's local space. The capsule height will be scaled by the actor's world scale.
|
||||
/// Sets the height of the capsule as a distance between the two sphere centers at the end of the capsule. The capsule height is measured in the object's local space and will be scaled by the actor's world scale.
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetHeight(float value);
|
||||
|
||||
@@ -116,6 +133,17 @@ public:
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetNonWalkableMode(NonWalkableModes value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the position origin placement mode.
|
||||
/// </summary>
|
||||
API_PROPERTY(Attributes="EditorOrder(216), DefaultValue(OriginModes.CapsuleCenter), EditorDisplay(\"Character Controller\")")
|
||||
OriginModes GetOriginMode() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the position origin placement mode.
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetOriginMode(OriginModes value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the step height. The character will step up a stair only if it is closer to the ground than the indicated value. This should not be greater than the Character Controller’s height or it will generate an error.
|
||||
/// </summary>
|
||||
@@ -194,6 +222,13 @@ public:
|
||||
/// <returns>The collision flags. It can be used to trigger various character animations.</returns>
|
||||
API_FUNCTION() CollisionFlags Move(const Vector3& displacement);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the character height and center position to ensure its feet position stays the same. This can be used to implement a 'crouch' functionality for example. Maintains the same actor position to stay in the middle of capsule by adjusting center of collider accordingly to height difference.
|
||||
/// </summary>
|
||||
/// <param name="height">The height of the capsule, measured in the object's local space.</param>
|
||||
/// <param name="radius">The radius of the capsule, measured in the object's local space.</param>
|
||||
API_FUNCTION() void Resize(float height, float radius);
|
||||
|
||||
protected:
|
||||
/// <summary>
|
||||
/// Creates the physics actor.
|
||||
@@ -210,6 +245,10 @@ protected:
|
||||
/// </summary>
|
||||
void UpdateSize() const;
|
||||
|
||||
private:
|
||||
Vector3 GetControllerPosition() const;
|
||||
void GetControllerSize(float& height, float& radius) const;
|
||||
|
||||
public:
|
||||
// [Collider]
|
||||
#if USE_EDITOR
|
||||
@@ -220,6 +259,7 @@ public:
|
||||
void AddMovement(const Vector3& translation, const Quaternion& rotation) override;
|
||||
bool CanAttach(RigidBody* rigidBody) const override;
|
||||
RigidBody* GetAttachedRigidBody() const override;
|
||||
void SetCenter(const Vector3& value) override;
|
||||
|
||||
// [IPhysicsActor]
|
||||
void OnActiveTransformChanged() override;
|
||||
|
||||
@@ -49,7 +49,7 @@ void Collider::SetIsTrigger(bool value)
|
||||
|
||||
void Collider::SetCenter(const Vector3& value)
|
||||
{
|
||||
if (Vector3::NearEqual(value, _center))
|
||||
if (value == _center)
|
||||
return;
|
||||
_center = value;
|
||||
if (_staticActor)
|
||||
@@ -62,7 +62,7 @@ void Collider::SetCenter(const Vector3& value)
|
||||
void Collider::SetContactOffset(float value)
|
||||
{
|
||||
value = Math::Clamp(value, 0.0f, 100.0f);
|
||||
if (Math::NearEqual(value, _contactOffset))
|
||||
if (value == _contactOffset)
|
||||
return;
|
||||
_contactOffset = value;
|
||||
if (_shape)
|
||||
@@ -205,7 +205,7 @@ void Collider::CreateShape()
|
||||
ASSERT(_shape == nullptr);
|
||||
|
||||
// Setup shape geometry
|
||||
_cachedScale = GetScale();
|
||||
_cachedScale = GetScale().GetAbsolute().MaxValue();
|
||||
CollisionShape shape;
|
||||
GetGeometry(shape);
|
||||
|
||||
@@ -222,7 +222,7 @@ void Collider::UpdateGeometry()
|
||||
return;
|
||||
|
||||
// Setup shape geometry
|
||||
_cachedScale = GetScale();
|
||||
_cachedScale = GetScale().GetAbsolute().MaxValue();
|
||||
CollisionShape shape;
|
||||
GetGeometry(shape);
|
||||
|
||||
@@ -427,8 +427,8 @@ void Collider::OnTransformChanged()
|
||||
}
|
||||
}
|
||||
|
||||
const Float3 scale = GetScale();
|
||||
if (!Float3::NearEqual(_cachedScale, scale))
|
||||
const float scale = GetScale().GetAbsolute().MaxValue();
|
||||
if (_cachedScale != scale)
|
||||
UpdateGeometry();
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ protected:
|
||||
bool _isTrigger;
|
||||
void* _shape;
|
||||
void* _staticActor;
|
||||
Float3 _cachedScale;
|
||||
float _cachedScale;
|
||||
float _contactOffset;
|
||||
Vector3 _cachedLocalPosePos;
|
||||
Quaternion _cachedLocalPoseRot;
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
/// <summary>
|
||||
/// Sets the center of the collider, measured in the object's local space.
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetCenter(const Vector3& value);
|
||||
API_PROPERTY() virtual void SetCenter(const Vector3& value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the contact offset. Colliders whose distance is less than the sum of their ContactOffset values will generate contacts. The contact offset must be positive. Contact offset allows the collision detection system to predictively enforce the contact constraint even when the objects are slightly separated.
|
||||
|
||||
@@ -131,7 +131,7 @@ void MeshCollider::UpdateBounds()
|
||||
void MeshCollider::GetGeometry(CollisionShape& collision)
|
||||
{
|
||||
// Prepare scale
|
||||
Float3 scale = _cachedScale;
|
||||
Float3 scale = _transform.Scale;
|
||||
const float minSize = 0.001f;
|
||||
Float3 scaleAbs = scale.GetAbsolute();
|
||||
if (scaleAbs.X < minSize)
|
||||
|
||||
@@ -10,7 +10,7 @@ SphereCollider::SphereCollider(const SpawnParams& params)
|
||||
|
||||
void SphereCollider::SetRadius(const float value)
|
||||
{
|
||||
if (Math::NearEqual(value, _radius))
|
||||
if (value == _radius)
|
||||
return;
|
||||
|
||||
_radius = value;
|
||||
@@ -67,8 +67,7 @@ void SphereCollider::UpdateBounds()
|
||||
|
||||
void SphereCollider::GetGeometry(CollisionShape& collision)
|
||||
{
|
||||
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||
const float radius = Math::Abs(_radius) * scaling;
|
||||
const float radius = Math::Abs(_radius) * _cachedScale;
|
||||
const float minSize = 0.001f;
|
||||
collision.SetSphere(Math::Max(radius, minSize));
|
||||
}
|
||||
|
||||
@@ -259,8 +259,7 @@ void SplineCollider::GetGeometry(CollisionShape& collision)
|
||||
}
|
||||
|
||||
// Prepare scale
|
||||
Float3 scale = _cachedScale;
|
||||
scale = Float3::Max(scale.GetAbsolute(), minSize);
|
||||
Float3 scale = Float3::Max(_transform.Scale.GetAbsolute(), minSize);
|
||||
|
||||
// TODO: add support for cooking collision for static splines in editor and reusing it in game
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ void DistanceJoint::SetFlags(DistanceJointFlag value)
|
||||
void DistanceJoint::SetMinDistance(float value)
|
||||
{
|
||||
value = Math::Clamp(value, 0.0f, _maxDistance);
|
||||
if (Math::NearEqual(value, _minDistance))
|
||||
if (value == _minDistance)
|
||||
return;
|
||||
_minDistance = value;
|
||||
if (_joint)
|
||||
@@ -35,7 +35,7 @@ void DistanceJoint::SetMinDistance(float value)
|
||||
void DistanceJoint::SetMaxDistance(float value)
|
||||
{
|
||||
value = Math::Max(_minDistance, value);
|
||||
if (Math::NearEqual(value, _maxDistance))
|
||||
if (value == _maxDistance)
|
||||
return;
|
||||
_maxDistance = value;
|
||||
if (_joint)
|
||||
@@ -45,7 +45,7 @@ void DistanceJoint::SetMaxDistance(float value)
|
||||
void DistanceJoint::SetTolerance(float value)
|
||||
{
|
||||
value = Math::Max(0.1f, value);
|
||||
if (Math::NearEqual(value, _tolerance))
|
||||
if (value == _tolerance)
|
||||
return;
|
||||
_tolerance = value;
|
||||
if (_joint)
|
||||
|
||||
@@ -59,7 +59,7 @@ API_STRUCT() struct HingeJointDrive
|
||||
public:
|
||||
bool operator==(const HingeJointDrive& other) const
|
||||
{
|
||||
return Math::NearEqual(Velocity, other.Velocity) && Math::NearEqual(ForceLimit, other.ForceLimit) && Math::NearEqual(GearRatio, other.GearRatio) && FreeSpin == other.FreeSpin;
|
||||
return Velocity == other.Velocity && ForceLimit == other.ForceLimit && GearRatio == other.GearRatio && FreeSpin == other.FreeSpin;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ Joint::Joint(const SpawnParams& params)
|
||||
|
||||
void Joint::SetBreakForce(float value)
|
||||
{
|
||||
if (Math::NearEqual(value, _breakForce))
|
||||
if (value == _breakForce)
|
||||
return;
|
||||
_breakForce = value;
|
||||
if (_joint)
|
||||
@@ -33,7 +33,7 @@ void Joint::SetBreakForce(float value)
|
||||
|
||||
void Joint::SetBreakTorque(float value)
|
||||
{
|
||||
if (Math::NearEqual(value, _breakTorque))
|
||||
if (value == _breakTorque)
|
||||
return;
|
||||
_breakTorque = value;
|
||||
if (_joint)
|
||||
@@ -61,7 +61,7 @@ void Joint::SetEnableAutoAnchor(bool value)
|
||||
|
||||
void Joint::SetTargetAnchor(const Vector3& value)
|
||||
{
|
||||
if (Vector3::NearEqual(value, _targetAnchor))
|
||||
if (value == _targetAnchor)
|
||||
return;
|
||||
_targetAnchor = value;
|
||||
if (_joint && !_enableAutoAnchor)
|
||||
|
||||
@@ -3160,10 +3160,9 @@ void* PhysicsBackend::CreateController(void* scene, IPhysicsActor* actor, Physic
|
||||
desc.material = (PxMaterial*)((PhysicalMaterial*)material->Instance)->GetPhysicsMaterial();
|
||||
else
|
||||
desc.material = DefaultMaterial;
|
||||
const float minSize = 0.001f;
|
||||
desc.height = Math::Max(height, minSize);
|
||||
desc.radius = Math::Max(radius - Math::Max(contactOffset, 0.0f), minSize);
|
||||
desc.stepOffset = Math::Min(stepOffset, desc.height + desc.radius * 2.0f - minSize);
|
||||
desc.height = height;
|
||||
desc.radius = radius;
|
||||
desc.stepOffset = Math::Min(stepOffset, desc.height + desc.radius * 2.0f - 0.001f);
|
||||
auto controllerPhysX = (PxCapsuleController*)scenePhysX->ControllerManager->createController(desc);
|
||||
PxRigidActor* actorPhysX = controllerPhysX->getActor();
|
||||
ASSERT(actorPhysX && actorPhysX->getNbShapes() == 1);
|
||||
@@ -3188,7 +3187,7 @@ void PhysicsBackend::SetControllerSize(void* controller, float radius, float hei
|
||||
{
|
||||
auto controllerPhysX = (PxCapsuleController*)controller;
|
||||
controllerPhysX->setRadius(radius);
|
||||
controllerPhysX->resize(height);
|
||||
controllerPhysX->setHeight(height);
|
||||
}
|
||||
|
||||
void PhysicsBackend::SetControllerSlopeLimit(void* controller, float value)
|
||||
@@ -3209,6 +3208,20 @@ void PhysicsBackend::SetControllerStepOffset(void* controller, float value)
|
||||
controllerPhysX->setStepOffset(value);
|
||||
}
|
||||
|
||||
Vector3 PhysicsBackend::GetControllerBasePosition(void* controller)
|
||||
{
|
||||
auto controllerPhysX = (PxCapsuleController*)controller;
|
||||
const Vector3 origin = SceneOrigins[controllerPhysX->getScene()];
|
||||
return P2C(controllerPhysX->getFootPosition()) + origin;
|
||||
}
|
||||
|
||||
void PhysicsBackend::SetControllerBasePosition(void* controller, const Vector3& value)
|
||||
{
|
||||
auto controllerPhysX = (PxCapsuleController*)controller;
|
||||
const Vector3 sceneOrigin = SceneOrigins[controllerPhysX->getScene()];
|
||||
controllerPhysX->setFootPosition(PxExtendedVec3(value.X - sceneOrigin.X, value.Y - sceneOrigin.Y, value.Z - sceneOrigin.Z));
|
||||
}
|
||||
|
||||
Vector3 PhysicsBackend::GetControllerUpDirection(void* controller)
|
||||
{
|
||||
auto controllerPhysX = (PxCapsuleController*)controller;
|
||||
|
||||
@@ -248,6 +248,8 @@ public:
|
||||
static void SetControllerSlopeLimit(void* controller, float value);
|
||||
static void SetControllerNonWalkableMode(void* controller, int32 value);
|
||||
static void SetControllerStepOffset(void* controller, float value);
|
||||
static Vector3 GetControllerBasePosition(void* controller);
|
||||
static void SetControllerBasePosition(void* controller, const Vector3& value);
|
||||
static Vector3 GetControllerUpDirection(void* controller);
|
||||
static void SetControllerUpDirection(void* controller, const Vector3& value);
|
||||
static Vector3 GetControllerPosition(void* controller);
|
||||
|
||||
@@ -59,7 +59,7 @@ API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings", NoConstructor) class
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// The default gravity force value (in cm^2/s).
|
||||
/// The default gravity value (in cm/(s^2)).
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(0), EditorDisplay(\"Simulation\")")
|
||||
Vector3 DefaultGravity = Vector3(0, -981.0f, 0);
|
||||
|
||||
@@ -42,17 +42,17 @@ void* WindowsPlatform::Instance = nullptr;
|
||||
extern "C" {
|
||||
static HANDLE dbgHelpLock;
|
||||
|
||||
void DbgHelpInit()
|
||||
void FlaxDbgHelpInit()
|
||||
{
|
||||
dbgHelpLock = CreateMutexW(nullptr, FALSE, nullptr);
|
||||
}
|
||||
|
||||
void DbgHelpLock()
|
||||
void FlaxDbgHelpLock()
|
||||
{
|
||||
WaitForSingleObject(dbgHelpLock, INFINITE);
|
||||
}
|
||||
|
||||
void DbgHelpUnlock()
|
||||
void FlaxDbgHelpUnlock()
|
||||
{
|
||||
ReleaseMutex(dbgHelpLock);
|
||||
}
|
||||
@@ -544,7 +544,7 @@ void WindowsPlatform::PreInit(void* hInstance)
|
||||
|
||||
#if CRASH_LOG_ENABLE
|
||||
TCHAR buffer[MAX_PATH] = { 0 };
|
||||
DbgHelpLock();
|
||||
FlaxDbgHelpLock();
|
||||
if (::GetModuleFileNameW(::GetModuleHandleW(nullptr), buffer, MAX_PATH))
|
||||
SymbolsPath.Add(StringUtils::GetDirectoryName(buffer));
|
||||
if (::GetEnvironmentVariableW(TEXT("_NT_SYMBOL_PATH"), buffer, MAX_PATH))
|
||||
@@ -553,7 +553,7 @@ void WindowsPlatform::PreInit(void* hInstance)
|
||||
options |= SYMOPT_LOAD_LINES | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS;
|
||||
SymSetOptions(options);
|
||||
OnSymbolsPathModified();
|
||||
DbgHelpUnlock();
|
||||
FlaxDbgHelpUnlock();
|
||||
#endif
|
||||
|
||||
GetWindowsVersion(WindowsName, VersionMajor, VersionMinor, VersionBuild);
|
||||
@@ -767,7 +767,7 @@ void WindowsPlatform::BeforeExit()
|
||||
void WindowsPlatform::Exit()
|
||||
{
|
||||
#if CRASH_LOG_ENABLE
|
||||
DbgHelpLock();
|
||||
FlaxDbgHelpLock();
|
||||
#if !TRACY_ENABLE
|
||||
if (SymInitialized)
|
||||
{
|
||||
@@ -776,7 +776,7 @@ void WindowsPlatform::Exit()
|
||||
}
|
||||
#endif
|
||||
SymbolsPath.Resize(0);
|
||||
DbgHelpUnlock();
|
||||
FlaxDbgHelpUnlock();
|
||||
#endif
|
||||
|
||||
// Unregister app class
|
||||
@@ -1278,14 +1278,14 @@ void* WindowsPlatform::LoadLibrary(const Char* filename)
|
||||
|
||||
#if CRASH_LOG_ENABLE
|
||||
// Refresh modules info during next stack trace collecting to have valid debug symbols information
|
||||
DbgHelpLock();
|
||||
FlaxDbgHelpLock();
|
||||
if (folder.HasChars() && !SymbolsPath.Contains(folder))
|
||||
{
|
||||
SymbolsPath.Add(folder);
|
||||
SymbolsPath.Last().Replace('/', '\\');
|
||||
OnSymbolsPathModified();
|
||||
}
|
||||
DbgHelpUnlock();
|
||||
FlaxDbgHelpUnlock();
|
||||
#endif
|
||||
|
||||
return handle;
|
||||
@@ -1296,7 +1296,7 @@ void* WindowsPlatform::LoadLibrary(const Char* filename)
|
||||
Array<PlatformBase::StackFrame> WindowsPlatform::GetStackFrames(int32 skipCount, int32 maxDepth, void* context)
|
||||
{
|
||||
Array<StackFrame> result;
|
||||
DbgHelpLock();
|
||||
FlaxDbgHelpLock();
|
||||
|
||||
// Initialize
|
||||
HANDLE process = GetCurrentProcess();
|
||||
@@ -1428,7 +1428,7 @@ Array<PlatformBase::StackFrame> WindowsPlatform::GetStackFrames(int32 skipCount,
|
||||
}
|
||||
}
|
||||
|
||||
DbgHelpUnlock();
|
||||
FlaxDbgHelpUnlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ void ForwardPass::Dispose()
|
||||
_shader = nullptr;
|
||||
}
|
||||
|
||||
void ForwardPass::Render(RenderContext& renderContext, GPUTexture* input, GPUTexture* output)
|
||||
void ForwardPass::Render(RenderContext& renderContext, GPUTexture*& input, GPUTexture*& output)
|
||||
{
|
||||
PROFILE_GPU_CPU("Forward");
|
||||
auto context = GPUDevice::Instance->GetMainContext();
|
||||
@@ -91,6 +91,16 @@ void ForwardPass::Render(RenderContext& renderContext, GPUTexture* input, GPUTex
|
||||
// Check if there is no objects to render or no resources ready
|
||||
auto& forwardList = mainCache->DrawCallsLists[(int32)DrawCallsListType::Forward];
|
||||
auto& distortionList = mainCache->DrawCallsLists[(int32)DrawCallsListType::Distortion];
|
||||
if ((forwardList.IsEmpty() && distortionList.IsEmpty())
|
||||
#if USE_EDITOR
|
||||
|| renderContext.View.Mode == ViewMode::PhysicsColliders
|
||||
#endif
|
||||
)
|
||||
{
|
||||
// Skip rendering
|
||||
Swap(input, output);
|
||||
return;
|
||||
}
|
||||
if (distortionList.IsEmpty() || checkIfSkipPass())
|
||||
{
|
||||
// Copy frame
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="input">Target with renderer frame ready for further processing.</param>
|
||||
/// <param name="output">The output frame.</param>
|
||||
void Render(RenderContext& renderContext, GPUTexture* input, GPUTexture* output);
|
||||
void Render(RenderContext& renderContext, GPUTexture*& input, GPUTexture*& output);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -240,6 +240,12 @@ void Renderer::Render(SceneRenderTask* task)
|
||||
| ViewFlags::ContactShadows
|
||||
| ViewFlags::DepthOfField);
|
||||
}
|
||||
|
||||
// Force Debug Draw usage in some specific views that depend on it
|
||||
if (renderContext.View.Mode == ViewMode::PhysicsColliders)
|
||||
{
|
||||
renderContext.View.Flags |= ViewFlags::DebugDraw;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Perform the actual rendering
|
||||
|
||||
@@ -27,6 +27,11 @@ namespace FlaxEngine.Json
|
||||
}
|
||||
}
|
||||
|
||||
internal interface ICustomValueEquals
|
||||
{
|
||||
bool ValueEquals(object other);
|
||||
}
|
||||
|
||||
partial class JsonSerializer
|
||||
{
|
||||
internal class SerializerCache
|
||||
@@ -262,7 +267,7 @@ namespace FlaxEngine.Json
|
||||
return true;
|
||||
if (objA == null || objB == null)
|
||||
return false;
|
||||
|
||||
|
||||
// Special case when saving reference to prefab object and the objects are different but the point to the same prefab object
|
||||
// In that case, skip saving reference as it's defined in prefab (will be populated via IdsMapping during deserialization)
|
||||
if (objA is SceneObject sceneA && objB is SceneObject sceneB && sceneA && sceneB && sceneA.HasPrefabLink && sceneB.HasPrefabLink)
|
||||
@@ -311,6 +316,8 @@ namespace FlaxEngine.Json
|
||||
return !bEnumerator.MoveNext();
|
||||
}
|
||||
|
||||
if (objA is ICustomValueEquals customValueEquals && objA.GetType() == objB.GetType())
|
||||
return customValueEquals.ValueEquals(objB);
|
||||
return objA.Equals(objB);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ void ChangeIds(rapidjson_flax::Value& obj, rapidjson_flax::Document& document, c
|
||||
else if (obj.IsString() && obj.GetStringLength() == 32)
|
||||
{
|
||||
auto value = JsonTools::GetGuid(obj);
|
||||
if (mapping.TryGet(value, value))
|
||||
if (value.IsValid() && mapping.TryGet(value, value))
|
||||
{
|
||||
// Unoptimized version:
|
||||
//obj.SetString(value.ToString(Guid::FormatType::N).ToSTD().c_str(), 32, document.GetAllocator());
|
||||
@@ -255,9 +255,8 @@ BoundingBox JsonTools::GetBoundingBox(const Value& value)
|
||||
|
||||
Guid JsonTools::GetGuid(const Value& value)
|
||||
{
|
||||
if (!value.IsString())
|
||||
if (!value.IsString() || value.GetStringLength() != 32)
|
||||
return Guid::Empty;
|
||||
CHECK_RETURN(value.GetStringLength() == 32, Guid::Empty);
|
||||
|
||||
// Split
|
||||
const char* a = value.GetString();
|
||||
@@ -267,10 +266,12 @@ Guid JsonTools::GetGuid(const Value& value)
|
||||
|
||||
// Parse
|
||||
Guid result;
|
||||
StringUtils::ParseHex(a, 8, &result.A);
|
||||
StringUtils::ParseHex(b, 8, &result.B);
|
||||
StringUtils::ParseHex(c, 8, &result.C);
|
||||
StringUtils::ParseHex(d, 8, &result.D);
|
||||
bool failed = StringUtils::ParseHex(a, 8, &result.A);
|
||||
failed |= StringUtils::ParseHex(b, 8, &result.B);
|
||||
failed |= StringUtils::ParseHex(c, 8, &result.C);
|
||||
failed |= StringUtils::ParseHex(d, 8, &result.D);
|
||||
if (failed)
|
||||
return Guid::Empty;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@ public:
|
||||
const auto member = node.FindMember(name);
|
||||
if (member != node.MemberEnd() && member->value.IsInt())
|
||||
{
|
||||
result = member->value.GetInt();
|
||||
result = (byte)member->value.GetInt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ public:
|
||||
const auto member = node.FindMember(name);
|
||||
if (member != node.MemberEnd() && member->value.IsInt())
|
||||
{
|
||||
result = member->value.GetInt();
|
||||
result = (uint32)member->value.GetInt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ public:
|
||||
const auto member = node.FindMember(name);
|
||||
if (member != node.MemberEnd() && member->value.IsInt())
|
||||
{
|
||||
result = member->value.GetInt();
|
||||
result = (int16)member->value.GetInt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ public:
|
||||
const auto member = node.FindMember(name);
|
||||
if (member != node.MemberEnd() && member->value.IsInt())
|
||||
{
|
||||
result = member->value.GetInt();
|
||||
result = (uint16)member->value.GetInt();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -240,6 +240,7 @@ void Terrain::DrawChunk(const RenderContext& renderContext, const Int2& patchCoo
|
||||
|
||||
void Terrain::DrawPhysicsDebug(RenderView& view)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
|
||||
{
|
||||
_patches[pathIndex]->DrawPhysicsDebug(view);
|
||||
@@ -260,7 +261,7 @@ void Terrain::SetScaleInLightmap(float value)
|
||||
|
||||
void Terrain::SetBoundsExtent(const Vector3& value)
|
||||
{
|
||||
if (Vector3::NearEqual(_boundsExtent, value))
|
||||
if (_boundsExtent == value)
|
||||
return;
|
||||
|
||||
_boundsExtent = value;
|
||||
@@ -891,7 +892,7 @@ void Terrain::OnTransformChanged()
|
||||
auto patch = _patches[i];
|
||||
patch->UpdateTransform();
|
||||
}
|
||||
if (!Float3::NearEqual(_cachedScale, _transform.Scale))
|
||||
if (_cachedScale != _transform.Scale)
|
||||
{
|
||||
_cachedScale = _transform.Scale;
|
||||
for (int32 i = 0; i < _patches.Count(); i++)
|
||||
|
||||
@@ -104,6 +104,8 @@ void TerrainPatch::Init(Terrain* terrain, int16 x, int16 z)
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
_collisionTriangles.Resize(0);
|
||||
SAFE_DELETE_GPU_RESOURCE(_collisionTrianglesBuffer);
|
||||
_collisionTrianglesBufferDirty = true;
|
||||
#endif
|
||||
_collisionVertices.Resize(0);
|
||||
}
|
||||
@@ -120,6 +122,9 @@ TerrainPatch::~TerrainPatch()
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
SAFE_DELETE_GPU_RESOURCE(_debugLines);
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
SAFE_DELETE_GPU_RESOURCE(_collisionTrianglesBuffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
RawDataAsset* TerrainPatch::GetHeightfield() const
|
||||
@@ -2225,6 +2230,8 @@ void TerrainPatch::DestroyCollision()
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
_collisionTriangles.Resize(0);
|
||||
SAFE_DELETE(_collisionTrianglesBuffer);
|
||||
_collisionTrianglesBufferDirty = true;
|
||||
#endif
|
||||
_collisionVertices.Resize(0);
|
||||
}
|
||||
@@ -2317,7 +2324,32 @@ void TerrainPatch::DrawPhysicsDebug(RenderView& view)
|
||||
return;
|
||||
if (view.Mode == ViewMode::PhysicsColliders)
|
||||
{
|
||||
DEBUG_DRAW_TRIANGLES(GetCollisionTriangles(), Color::DarkOliveGreen, 0, true);
|
||||
const auto& triangles = GetCollisionTriangles();
|
||||
typedef DebugDraw::Vertex Vertex;
|
||||
if (!_collisionTrianglesBuffer)
|
||||
_collisionTrianglesBuffer = GPUDevice::Instance->CreateBuffer(TEXT("Terrain.CollisionTriangles"));
|
||||
const uint32 count = triangles.Count();
|
||||
if (_collisionTrianglesBuffer->GetElementsCount() != count)
|
||||
{
|
||||
if (_collisionTrianglesBuffer->Init(GPUBufferDescription::Vertex(Vertex::GetLayout(), sizeof(Vertex), count)))
|
||||
return;
|
||||
_collisionTrianglesBufferDirty = true;
|
||||
}
|
||||
if (_collisionTrianglesBufferDirty)
|
||||
{
|
||||
const Color32 color(Color::DarkOliveGreen);
|
||||
Array<Vertex> vertices;
|
||||
vertices.Resize((int32)count);
|
||||
const Vector3* src = triangles.Get();
|
||||
Vertex* dst = vertices.Get();
|
||||
for (uint32 i = 0; i < count; i++)
|
||||
{
|
||||
dst[i] = { (Float3)src[i], color };
|
||||
}
|
||||
_collisionTrianglesBuffer->SetData(vertices.Get(), _collisionTrianglesBuffer->GetSize());
|
||||
_collisionTrianglesBufferDirty = false;
|
||||
}
|
||||
DebugDraw::DrawTriangles(_collisionTrianglesBuffer, Matrix::Identity, 0, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2351,6 +2383,7 @@ const Array<Vector3>& TerrainPatch::GetCollisionTriangles()
|
||||
PhysicsBackend::GetHeightFieldSize(_physicsHeightField, rows, cols);
|
||||
|
||||
_collisionTriangles.Resize((rows - 1) * (cols - 1) * 6);
|
||||
_collisionTrianglesBufferDirty = true;
|
||||
Vector3* data = _collisionTriangles.Get();
|
||||
|
||||
#define GET_VERTEX(x, y) Vector3 v##x##y((float)(row + (x)), PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, row + (x), col + (y)) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y))); Vector3::Transform(v##x##y, world, v##x##y)
|
||||
|
||||
@@ -49,6 +49,8 @@ private:
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
Array<Vector3> _collisionTriangles; // TODO: large-worlds
|
||||
class GPUBuffer* _collisionTrianglesBuffer = nullptr;
|
||||
bool _collisionTrianglesBufferDirty = true;
|
||||
#endif
|
||||
Array<Float3> _collisionVertices; // TODO: large-worlds
|
||||
|
||||
|
||||
@@ -11,13 +11,13 @@ namespace FlaxEngine.Tests
|
||||
[Test]
|
||||
public void TestConversion()
|
||||
{
|
||||
Assert.AreEqual(Float4.Zero, new FloatR10G10B10A2(Float4.Zero).ToFloat4());
|
||||
Assert.AreEqual(Float4.One, new FloatR10G10B10A2(Float4.One).ToFloat4());
|
||||
Assert.AreEqual(new Float4(0.5004888f, 0.5004888f, 0.5004888f, 0.666667f), new FloatR10G10B10A2(new Float4(0.5f)).ToFloat4());
|
||||
Assert.AreEqual(new Float4(1, 0, 0, 0), new FloatR10G10B10A2(new Float4(1, 0, 0, 0)).ToFloat4());
|
||||
Assert.AreEqual(new Float4(0, 1, 0, 0), new FloatR10G10B10A2(new Float4(0, 1, 0, 0)).ToFloat4());
|
||||
Assert.AreEqual(new Float4(0, 0, 1, 0), new FloatR10G10B10A2(new Float4(0, 0, 1, 0)).ToFloat4());
|
||||
Assert.AreEqual(new Float4(0, 0, 0, 1), new FloatR10G10B10A2(new Float4(0, 0, 0, 1)).ToFloat4());
|
||||
Assert.IsTrue(Float4.NearEqual(Float4.Zero, new FloatR10G10B10A2(Float4.Zero).ToFloat4()));
|
||||
Assert.IsTrue(Float4.NearEqual(Float4.One, new FloatR10G10B10A2(Float4.One).ToFloat4()));
|
||||
Assert.IsTrue(Float4.NearEqual(new Float4(0.5004888f, 0.5004888f, 0.5004888f, 0.666667f), new FloatR10G10B10A2(new Float4(0.5f)).ToFloat4()));
|
||||
Assert.IsTrue(Float4.NearEqual(new Float4(1, 0, 0, 0), new FloatR10G10B10A2(new Float4(1, 0, 0, 0)).ToFloat4()));
|
||||
Assert.IsTrue(Float4.NearEqual(new Float4(0, 1, 0, 0), new FloatR10G10B10A2(new Float4(0, 1, 0, 0)).ToFloat4()));
|
||||
Assert.IsTrue(Float4.NearEqual(new Float4(0, 0, 1, 0), new FloatR10G10B10A2(new Float4(0, 0, 1, 0)).ToFloat4()));
|
||||
Assert.IsTrue(Float4.NearEqual(new Float4(0, 0, 0, 1), new FloatR10G10B10A2(new Float4(0, 0, 0, 1)).ToFloat4()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,13 +11,13 @@ namespace FlaxEngine.Tests
|
||||
[Test]
|
||||
public void TestConversion()
|
||||
{
|
||||
Assert.AreEqual(Float3.Zero, new FloatR11G11B10(Float3.Zero).ToFloat3());
|
||||
Assert.AreEqual(Float3.One, new FloatR11G11B10(Float3.One).ToFloat3());
|
||||
Assert.AreEqual(new Float3(0.5f, 0.5f, 0.5f), new FloatR11G11B10(new Float3(0.5f)).ToFloat3());
|
||||
Assert.AreEqual(new Float3(1, 0, 0), new FloatR11G11B10(new Float3(1, 0, 0)).ToFloat3());
|
||||
Assert.AreEqual(new Float3(0, 1, 0), new FloatR11G11B10(new Float3(0, 1, 0)).ToFloat3());
|
||||
Assert.AreEqual(new Float3(0, 0, 1), new FloatR11G11B10(new Float3(0, 0, 1)).ToFloat3());
|
||||
Assert.AreEqual(new Float3(10, 11, 12), new FloatR11G11B10(new Float3(10, 11, 12)).ToFloat3());
|
||||
Assert.IsTrue(Float3.NearEqual(Float3.Zero, new FloatR11G11B10(Float3.Zero).ToFloat3()));
|
||||
Assert.IsTrue(Float3.NearEqual(Float3.One, new FloatR11G11B10(Float3.One).ToFloat3()));
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(0.5f, 0.5f, 0.5f), new FloatR11G11B10(new Float3(0.5f)).ToFloat3()));
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(1, 0, 0), new FloatR11G11B10(new Float3(1, 0, 0)).ToFloat3()));
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(0, 1, 0), new FloatR11G11B10(new Float3(0, 1, 0)).ToFloat3()));
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(0, 0, 1), new FloatR11G11B10(new Float3(0, 0, 1)).ToFloat3()));
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(10, 11, 12), new FloatR11G11B10(new Float3(10, 11, 12)).ToFloat3()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,9 +44,9 @@ void TestsRunnerService::Update()
|
||||
LOG(Info, "Running Flax Tests...");
|
||||
const int result = Catch::Session().run();
|
||||
if (result == 0)
|
||||
LOG(Info, "Result: {0}", result);
|
||||
LOG(Info, "Flax Tests result: {0}", result);
|
||||
else
|
||||
LOG(Error, "Result: {0}", result);
|
||||
LOG(Error, "Flax Tests result: {0}", result);
|
||||
Log::Logger::WriteFloor();
|
||||
Engine::RequestExit(result);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/ScopeExit.h"
|
||||
#include "Engine/Level/Actor.h"
|
||||
#include "Engine/Level/Actors/EmptyActor.h"
|
||||
#include "Engine/Level/Actors/DirectionalLight.h"
|
||||
@@ -27,6 +28,7 @@ TEST_CASE("Prefabs")
|
||||
// Create Prefab B with two children attached to the root
|
||||
AssetReference<Prefab> prefabB = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabB);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabB); };
|
||||
Guid id;
|
||||
Guid::Parse("665bb01c49a3370f14a023b5395de261", id);
|
||||
prefabB->ChangeID(id);
|
||||
@@ -55,6 +57,7 @@ TEST_CASE("Prefabs")
|
||||
// Create Prefab A with nested Prefab B attached to the root
|
||||
AssetReference<Prefab> prefabA = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabA);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabA); };
|
||||
Guid::Parse("02524a044184af56b6c664a0f98bd761", id);
|
||||
prefabA->ChangeID(id);
|
||||
auto prefabAInit = prefabA->Init(Prefab::TypeName,
|
||||
@@ -123,8 +126,6 @@ TEST_CASE("Prefabs")
|
||||
// Cleanup
|
||||
instanceA->DeleteObject();
|
||||
instanceB->DeleteObject();
|
||||
Content::DeleteAsset(prefabA);
|
||||
Content::DeleteAsset(prefabB);
|
||||
}
|
||||
SECTION("Test Adding Object in Nested Prefab")
|
||||
{
|
||||
@@ -133,6 +134,7 @@ TEST_CASE("Prefabs")
|
||||
// Create Prefab B with just root object
|
||||
AssetReference<Prefab> prefabB = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabB);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabB); };
|
||||
Guid id;
|
||||
Guid::Parse("25dbe4b0416be0777a6ce59e8788b10f", id);
|
||||
prefabB->ChangeID(id);
|
||||
@@ -149,6 +151,7 @@ TEST_CASE("Prefabs")
|
||||
// Create Prefab A with two nested Prefab B attached to the root
|
||||
AssetReference<Prefab> prefabA = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabA);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabA); };
|
||||
Guid::Parse("4cb744714f746e31855f41815612d14b", id);
|
||||
prefabA->ChangeID(id);
|
||||
auto prefabAInit = prefabA->Init(Prefab::TypeName,
|
||||
@@ -243,8 +246,6 @@ TEST_CASE("Prefabs")
|
||||
// Cleanup
|
||||
instanceA->DeleteObject();
|
||||
instanceB->DeleteObject();
|
||||
Content::DeleteAsset(prefabA);
|
||||
Content::DeleteAsset(prefabB);
|
||||
}
|
||||
SECTION("Test Syncing Changes In Nested Prefab Instance")
|
||||
{
|
||||
@@ -253,6 +254,7 @@ TEST_CASE("Prefabs")
|
||||
// Create TestActor prefab with just root object
|
||||
AssetReference<Prefab> testActorPrefab = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(testActorPrefab);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(testActorPrefab); };
|
||||
Guid id;
|
||||
Guid::Parse("7691e981482f2a486e10cfae149e07d3", id);
|
||||
testActorPrefab->ChangeID(id);
|
||||
@@ -269,6 +271,7 @@ TEST_CASE("Prefabs")
|
||||
// Create NestedActor prefab that inherits from TestActor prefab
|
||||
AssetReference<Prefab> nestedActorPrefab = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(nestedActorPrefab);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(nestedActorPrefab); };
|
||||
Guid::Parse("1d521df4465ad849e274748c6d14b703", id);
|
||||
nestedActorPrefab->ChangeID(id);
|
||||
auto nestedActorPrefabInit = nestedActorPrefab->Init(Prefab::TypeName,
|
||||
@@ -328,8 +331,6 @@ TEST_CASE("Prefabs")
|
||||
// Cleanup
|
||||
nestedActor->DeleteObject();
|
||||
testActor->DeleteObject();
|
||||
Content::DeleteAsset(nestedActorPrefab);
|
||||
Content::DeleteAsset(testActorPrefab);
|
||||
}
|
||||
SECTION("Test Loading Nested Prefab After Changing Root")
|
||||
{
|
||||
@@ -338,6 +339,7 @@ TEST_CASE("Prefabs")
|
||||
// Create base prefab with 3 objects
|
||||
AssetReference<Prefab> prefabBase = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabBase);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabBase); };
|
||||
Guid id;
|
||||
Guid::Parse("2b3334524c696dcfa93cabacd2a4f404", id);
|
||||
prefabBase->ChangeID(id);
|
||||
@@ -366,6 +368,7 @@ TEST_CASE("Prefabs")
|
||||
// Create nested prefab but with 'old' state where root object is different
|
||||
AssetReference<Prefab> prefabNested = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabNested);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabNested); };
|
||||
Guid::Parse("a71447e947cbd2deea018a8377636ce6", id);
|
||||
prefabNested->ChangeID(id);
|
||||
auto prefabNestedInit = prefabNested->Init(Prefab::TypeName,
|
||||
@@ -411,8 +414,6 @@ TEST_CASE("Prefabs")
|
||||
// Cleanup
|
||||
instanceNested->DeleteObject();
|
||||
instanceBase->DeleteObject();
|
||||
Content::DeleteAsset(prefabNested);
|
||||
Content::DeleteAsset(prefabBase);
|
||||
}
|
||||
SECTION("Test Loading Nested Prefab After Changing and Deleting Root")
|
||||
{
|
||||
@@ -421,6 +422,7 @@ TEST_CASE("Prefabs")
|
||||
// Create base prefab with 1 object
|
||||
AssetReference<Prefab> prefabBase = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabBase);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabBase); };
|
||||
Guid id;
|
||||
Guid::Parse("3b3334524c696dcfa93cabacd2a4f404", id);
|
||||
prefabBase->ChangeID(id);
|
||||
@@ -455,6 +457,7 @@ TEST_CASE("Prefabs")
|
||||
// Create nested prefab but with 'old' state where root object is different
|
||||
AssetReference<Prefab> prefabNested1 = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabNested1);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabNested1); };
|
||||
Guid::Parse("671447e947cbd2deea018a8377636ce6", id);
|
||||
prefabNested1->ChangeID(id);
|
||||
auto prefabNestedInit1 = prefabNested1->Init(Prefab::TypeName,
|
||||
@@ -491,6 +494,7 @@ TEST_CASE("Prefabs")
|
||||
// Create nested prefab but with 'old' state where root object is different and doesn't exist anymore
|
||||
AssetReference<Prefab> prefabNested2 = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabNested2);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabNested2); };
|
||||
Guid::Parse("b71447e947cbd2deea018a8377636ce6", id);
|
||||
prefabNested2->ChangeID(id);
|
||||
auto prefabNestedInit2 = prefabNested2->Init(Prefab::TypeName,
|
||||
@@ -555,9 +559,6 @@ TEST_CASE("Prefabs")
|
||||
instanceNested2->DeleteObject();
|
||||
instanceNested1->DeleteObject();
|
||||
instanceBase->DeleteObject();
|
||||
Content::DeleteAsset(prefabNested2);
|
||||
Content::DeleteAsset(prefabNested1);
|
||||
Content::DeleteAsset(prefabBase);
|
||||
}
|
||||
SECTION("Test Applying Prefab Change To Object References")
|
||||
{
|
||||
@@ -566,6 +567,7 @@ TEST_CASE("Prefabs")
|
||||
// Create Prefab
|
||||
AssetReference<Prefab> prefab = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefab);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefab); };
|
||||
Guid id;
|
||||
Guid::Parse("690e55514cd6fdc2a269429a2bf84133", id);
|
||||
prefab->ChangeID(id);
|
||||
@@ -612,7 +614,6 @@ TEST_CASE("Prefabs")
|
||||
// Cleanup
|
||||
instanceA->DeleteObject();
|
||||
instanceB->DeleteObject();
|
||||
Content::DeleteAsset(prefab);
|
||||
}
|
||||
SECTION("Test Applying Prefab With Missing Nested Prefab")
|
||||
{
|
||||
@@ -637,6 +638,7 @@ TEST_CASE("Prefabs")
|
||||
// Create Prefab A with nested Prefab B attached to the root
|
||||
AssetReference<Prefab> prefabA = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabA);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabA); };
|
||||
Guid::Parse("4cb744714f746e31855f41815612d14b", id);
|
||||
prefabA->ChangeID(id);
|
||||
auto prefabAInit = prefabA->Init(Prefab::TypeName,
|
||||
@@ -685,7 +687,6 @@ TEST_CASE("Prefabs")
|
||||
instanceA->DeleteObject();
|
||||
instanceB->DeleteObject();
|
||||
instanceC->DeleteObject();
|
||||
Content::DeleteAsset(prefabA);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,10 @@ namespace FlaxEngine.Tests
|
||||
[Test]
|
||||
public void TestEuler()
|
||||
{
|
||||
Assert.AreEqual(Quaternion.Euler(90, 0, 0), new Quaternion(0.7071068f, 0, 0, 0.7071068f));
|
||||
Assert.AreEqual(Quaternion.Euler(25, 0, 10), new Quaternion(0.215616f, -0.018864f, 0.0850898f, 0.9725809f));
|
||||
Assert.AreEqual(new Float3(25, 0, 10), Quaternion.Euler(25, 0, 10).EulerAngles);
|
||||
Assert.AreEqual(new Float3(25, -5, 10), Quaternion.Euler(25, -5, 10).EulerAngles);
|
||||
Assert.IsTrue(Quaternion.NearEqual(Quaternion.Euler(90, 0, 0), new Quaternion(0.7071068f, 0, 0, 0.7071068f)));
|
||||
Assert.IsTrue(Quaternion.NearEqual(Quaternion.Euler(25, 0, 10), new Quaternion(0.215616f, -0.018864f, 0.0850898f, 0.9725809f)));
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(25, 0, 10), Quaternion.Euler(25, 0, 10).EulerAngles, 0.00001f));
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(25, -5, 10), Quaternion.Euler(25, -5, 10).EulerAngles, 0.00001f));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -33,7 +33,7 @@ namespace FlaxEngine.Tests
|
||||
var delta = Quaternion.Euler(0, 10, 0);
|
||||
for (int i = 0; i < 9; i++)
|
||||
q *= delta;
|
||||
Assert.AreEqual(Quaternion.Euler(0, 90, 0), q);
|
||||
Assert.IsTrue(Quaternion.NearEqual(Quaternion.Euler(0, 90, 0), q));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,9 +68,9 @@ namespace FlaxEngine.Tests
|
||||
t1.LocalToWorld(new Vector3[1] { t2.Translation }, a4T);
|
||||
Vector3 a4 = a4T[0];
|
||||
|
||||
Assert.AreEqual(a1.Translation, a2);
|
||||
Assert.AreEqual(a2, a3);
|
||||
Assert.AreEqual(a2, a4);
|
||||
Assert.IsTrue(Vector3.NearEqual(a1.Translation, a2));
|
||||
Assert.IsTrue(Vector3.NearEqual(a2, a3));
|
||||
Assert.IsTrue(Vector3.NearEqual(a2, a4));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -100,9 +100,9 @@ namespace FlaxEngine.Tests
|
||||
t1.WorldToLocal(new Vector3[1] { t2.Translation }, a4T);
|
||||
Float3 a4 = a4T[0];
|
||||
|
||||
Assert.AreEqual((Float3)a1.Translation, a2);
|
||||
Assert.AreEqual(a2, a3);
|
||||
Assert.AreEqual(a2, a4);
|
||||
Assert.IsTrue(Float3.NearEqual((Float3)a1.Translation, a2));
|
||||
Assert.IsTrue(Float3.NearEqual(a2, a3, 0.0001f));
|
||||
Assert.IsTrue(Float3.NearEqual(a2, a4));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -113,28 +113,28 @@ namespace FlaxEngine.Tests
|
||||
{
|
||||
Transform trans = new Transform(new Vector3(1, 2, 3));
|
||||
|
||||
Assert.AreEqual(new Float3(1, 2, 3), (Float3)trans.LocalToWorld(new Float3(0, 0, 0)));
|
||||
Assert.AreEqual(new Float3(4, 4, 4), (Float3)trans.LocalToWorld(new Float3(3, 2, 1)));
|
||||
Assert.AreEqual(new Float3(-1, -2, -3), (Float3)trans.WorldToLocal(new Float3(0, 0, 0)));
|
||||
Assert.AreEqual(new Float3(0, 0, 0), (Float3)trans.WorldToLocal(new Float3(1, 2, 3)));
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(1, 2, 3), (Float3)trans.LocalToWorld(new Float3(0, 0, 0))));
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(4, 4, 4), (Float3)trans.LocalToWorld(new Float3(3, 2, 1))));
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(-1, -2, -3), (Float3)trans.WorldToLocal(new Float3(0, 0, 0))));
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(0, 0, 0), (Float3)trans.WorldToLocal(new Float3(1, 2, 3))));
|
||||
|
||||
trans = new Transform(Vector3.Zero, Quaternion.Euler(0, 90, 0));
|
||||
Assert.AreEqual(new Float3(0, 2, -1), (Float3)trans.LocalToWorld(new Float3(1, 2, 0)));
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(0, 2, -1), (Float3)trans.LocalToWorld(new Float3(1, 2, 0))));
|
||||
|
||||
trans.Translation = new Vector3(1, 0, 0);
|
||||
trans.Orientation = Quaternion.RotationX((float)Math.PI * 0.5f);
|
||||
trans.Scale = new Vector3(2, 2, 2);
|
||||
Assert.AreEqual(new Float3(1, 0, 2), (Float3)trans.LocalToWorld(new Float3(0, 1, 0)));
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(1, 0, 2), (Float3)trans.LocalToWorld(new Float3(0, 1, 0))));
|
||||
|
||||
Transform t1 = trans.LocalToWorld(Transform.Identity);
|
||||
Assert.AreEqual(new Float3(1.0f, 0, 0), (Float3)t1.Translation);
|
||||
Assert.AreEqual(Quaternion.RotationX((float)Math.PI * 0.5f), t1.Orientation);
|
||||
Assert.AreEqual(new Float3(2.0f, 2.0f, 2.0f), t1.Scale);
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(1.0f, 0, 0), (Float3)t1.Translation));
|
||||
Assert.IsTrue(Quaternion.NearEqual(Quaternion.RotationX((float)Math.PI * 0.5f), t1.Orientation));
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(2.0f, 2.0f, 2.0f), t1.Scale));
|
||||
|
||||
Transform t2 = trans.WorldToLocal(Transform.Identity);
|
||||
Assert.AreEqual(new Float3(-0.5f, 0, 0), (Float3)t2.Translation);
|
||||
Assert.AreEqual(Quaternion.RotationX((float)Math.PI * -0.5f), t2.Orientation);
|
||||
Assert.AreEqual(new Float3(0.5f, 0.5f, 0.5f), t2.Scale);
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(-0.5f, 0, 0), (Float3)t2.Translation));
|
||||
Assert.IsTrue(Quaternion.NearEqual(Quaternion.RotationX((float)Math.PI * -0.5f), t2.Orientation));
|
||||
Assert.IsTrue(Float3.NearEqual(new Float3(0.5f, 0.5f, 0.5f), t2.Scale));
|
||||
|
||||
var rand = new Random(10);
|
||||
for (int i = 0; i < 10; i++)
|
||||
|
||||
@@ -40,7 +40,7 @@ void Task::Cancel()
|
||||
bool Task::Wait(double timeoutMilliseconds) const
|
||||
{
|
||||
PROFILE_CPU();
|
||||
double startTime = Platform::GetTimeSeconds() * 0.001;
|
||||
const double startTime = Platform::GetTimeSeconds();
|
||||
|
||||
// TODO: no active waiting! use a semaphore!
|
||||
|
||||
@@ -54,7 +54,7 @@ bool Task::Wait(double timeoutMilliseconds) const
|
||||
// Wait for child if has
|
||||
if (_continueWith)
|
||||
{
|
||||
auto spendTime = Platform::GetTimeSeconds() * 0.001 - startTime;
|
||||
const auto spendTime = (Platform::GetTimeSeconds() - startTime) * 1000.0;
|
||||
return _continueWith->Wait(timeoutMilliseconds - spendTime);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ bool Task::Wait(double timeoutMilliseconds) const
|
||||
return true;
|
||||
|
||||
Platform::Sleep(1);
|
||||
} while (timeoutMilliseconds <= 0.0 || Platform::GetTimeSeconds() * 0.001 - startTime < timeoutMilliseconds);
|
||||
} while (timeoutMilliseconds <= 0.0 || (Platform::GetTimeSeconds() - startTime) * 1000.0 < timeoutMilliseconds);
|
||||
|
||||
// Timeout reached!
|
||||
LOG(Warning, "\'{0}\' has timed out. Wait time: {1} ms", ToString(), timeoutMilliseconds);
|
||||
|
||||
@@ -676,6 +676,9 @@ void ModelTool::Options::Serialize(SerializeStream& stream, const void* otherObj
|
||||
SERIALIZE(CalculateBoneOffsetMatrices);
|
||||
SERIALIZE(LightmapUVsSource);
|
||||
SERIALIZE(CollisionMeshesPrefix);
|
||||
SERIALIZE(CollisionType);
|
||||
SERIALIZE(PositionFormat);
|
||||
SERIALIZE(TexCoordFormat);
|
||||
SERIALIZE(Scale);
|
||||
SERIALIZE(Rotation);
|
||||
SERIALIZE(Translation);
|
||||
@@ -727,6 +730,9 @@ void ModelTool::Options::Deserialize(DeserializeStream& stream, ISerializeModifi
|
||||
DESERIALIZE(CalculateBoneOffsetMatrices);
|
||||
DESERIALIZE(LightmapUVsSource);
|
||||
DESERIALIZE(CollisionMeshesPrefix);
|
||||
DESERIALIZE(CollisionType);
|
||||
DESERIALIZE(PositionFormat);
|
||||
DESERIALIZE(TexCoordFormat);
|
||||
DESERIALIZE(Scale);
|
||||
DESERIALIZE(Rotation);
|
||||
DESERIALIZE(Translation);
|
||||
@@ -1137,6 +1143,10 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option
|
||||
if (ImportData(path, data, options, errorMsg))
|
||||
return true;
|
||||
|
||||
// Copy over data format options
|
||||
data.PositionFormat = (ModelData::PositionFormats)options.PositionFormat;
|
||||
data.TexCoordFormat = (ModelData::TexCoordFormats)options.TexCoordFormat;
|
||||
|
||||
// Validate result data
|
||||
if (EnumHasAnyFlags(options.ImportTypes, ImportDataTypes::Geometry))
|
||||
{
|
||||
@@ -1921,9 +1931,43 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option
|
||||
auto mesh = lod.Meshes[i];
|
||||
if (mesh->Name.StartsWith(options.CollisionMeshesPrefix, StringSearchCase::IgnoreCase))
|
||||
{
|
||||
// Remove material slot used by this mesh (if no other mesh else uses it)
|
||||
int32 materialSlotUsageCount = 0;
|
||||
for (const auto& e : data.LODs)
|
||||
{
|
||||
for (const MeshData* q : e.Meshes)
|
||||
{
|
||||
if (q->MaterialSlotIndex == mesh->MaterialSlotIndex)
|
||||
materialSlotUsageCount++;
|
||||
}
|
||||
}
|
||||
if (materialSlotUsageCount == 1)
|
||||
{
|
||||
data.Materials.RemoveAt(mesh->MaterialSlotIndex);
|
||||
|
||||
// Fixup linkage of other meshes to materials
|
||||
for (auto& e : data.LODs)
|
||||
{
|
||||
for (MeshData* q : e.Meshes)
|
||||
{
|
||||
if (q->MaterialSlotIndex > mesh->MaterialSlotIndex)
|
||||
{
|
||||
q->MaterialSlotIndex--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove data linkage
|
||||
mesh->NodeIndex = 0;
|
||||
mesh->MaterialSlotIndex = 0;
|
||||
|
||||
// Add mesh to collision
|
||||
if (collisionModel.LODs.Count() == 0)
|
||||
collisionModel.LODs.AddOne();
|
||||
collisionModel.LODs[0].Meshes.Add(mesh);
|
||||
|
||||
// Remove mesh from model
|
||||
lod.Meshes.RemoveAtKeepOrder(i);
|
||||
if (lod.Meshes.IsEmpty())
|
||||
break;
|
||||
|
||||
@@ -142,6 +142,28 @@ public:
|
||||
ExtractCenterOfMass = 2,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Declares the imported vertex positions data formats.
|
||||
/// </summary>
|
||||
API_ENUM(Attributes="HideInEditor") enum class PositionFormat
|
||||
{
|
||||
// XYZ channels with 32-bit precision (12 bytes per vertex).
|
||||
Float32,
|
||||
// XYZ(W) channels with 12-bit precision (8 bytes per vertex).
|
||||
Float16,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Declares the imported vertex texture coordinates data formats.
|
||||
/// </summary>
|
||||
API_ENUM(Attributes="HideInEditor") enum class TexCoordFormats
|
||||
{
|
||||
// XY channels with 16-bit precision (4 bytes per vertex).
|
||||
Float16,
|
||||
// XY channels with 8-bit precision (2 bytes per vertex). Valid only for normalized UVs within range [0; 1], scaled or negative UVs won't work.
|
||||
UNorm8,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Model import options.
|
||||
/// </summary>
|
||||
@@ -201,6 +223,14 @@ public:
|
||||
API_FIELD(Attributes="EditorOrder(105), EditorDisplay(\"Geometry\"), VisibleIf(nameof(ShowGeometry))")
|
||||
CollisionDataType CollisionType = CollisionDataType::ConvexMesh;
|
||||
|
||||
public:
|
||||
// The imported vertex positions data format to use by meshes. Changing this affects memory usage of the mesh data, performance and overall quality.
|
||||
API_FIELD(Attributes = "EditorOrder(200), EditorDisplay(\"Data Format\"), VisibleIf(nameof(ShowGeometry))")
|
||||
PositionFormat PositionFormat = PositionFormat::Float32;
|
||||
// The imported vertex texture coordinates data format to use by meshes. Changing this affects memory usage of the mesh data, performance and overall quality.
|
||||
API_FIELD(Attributes = "EditorOrder(205), EditorDisplay(\"Data Format\"), VisibleIf(nameof(ShowGeometry))")
|
||||
TexCoordFormats TexCoordFormat = TexCoordFormats::Float16;
|
||||
|
||||
public: // Transform
|
||||
|
||||
// Custom uniform import scale.
|
||||
|
||||
@@ -298,9 +298,13 @@ namespace FlaxEngine.GUI
|
||||
color *= 0.85f;
|
||||
Render2D.DrawText(font, text, color, ref _layout, TextMaterial);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(_watermarkText))
|
||||
else
|
||||
{
|
||||
Render2D.DrawText(font, _watermarkText, WatermarkTextColor, ref _layout, TextMaterial);
|
||||
text = _watermarkText;
|
||||
if (text?.Length > 0)
|
||||
{
|
||||
Render2D.DrawText(font, _watermarkText, WatermarkTextColor, ref _layout, TextMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
// Caret
|
||||
|
||||
@@ -51,6 +51,11 @@ namespace FlaxEngine.GUI
|
||||
/// </summary>
|
||||
protected float _cachedHeight = 16.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The items spacing.
|
||||
/// </summary>
|
||||
protected float _itemsSpacing = 2.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The items margin.
|
||||
/// </summary>
|
||||
@@ -168,9 +173,9 @@ namespace FlaxEngine.GUI
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item slots margin (the space between items).
|
||||
/// Gets or sets the item slots margin (the space around items).
|
||||
/// </summary>
|
||||
[EditorOrder(10), Tooltip("The item slots margin (the space between items).")]
|
||||
[EditorOrder(10)]
|
||||
public Margin ItemsMargin
|
||||
{
|
||||
get => _itemsMargin;
|
||||
@@ -184,6 +189,23 @@ namespace FlaxEngine.GUI
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item slots spacing (the margin between items).
|
||||
/// </summary>
|
||||
[EditorOrder(11)]
|
||||
public float ItemsSpacing
|
||||
{
|
||||
get => _itemsSpacing;
|
||||
set
|
||||
{
|
||||
if (!Mathf.NearEqual(_itemsSpacing, value))
|
||||
{
|
||||
_itemsSpacing = value;
|
||||
PerformLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the panel close/open animation duration (in seconds).
|
||||
/// </summary>
|
||||
@@ -563,25 +585,27 @@ namespace FlaxEngine.GUI
|
||||
var slotsLeft = clientArea.Left + slotsMargin.Left;
|
||||
var slotsWidth = clientArea.Width - slotsMargin.Width;
|
||||
float minHeight = HeaderHeight;
|
||||
float y = clientArea.Top;
|
||||
float height = clientArea.Top + dropOffset;
|
||||
float y = clientArea.Top + slotsMargin.Top;
|
||||
bool anyAdded = false;
|
||||
for (int i = 0; i < _children.Count; i++)
|
||||
{
|
||||
Control c = _children[i];
|
||||
if (c.IsScrollable && c.Visible)
|
||||
{
|
||||
var h = c.Height;
|
||||
y += slotsMargin.Top;
|
||||
|
||||
c.Bounds = new Rectangle(slotsLeft, y, slotsWidth, h);
|
||||
|
||||
h += slotsMargin.Bottom;
|
||||
h += _itemsSpacing;
|
||||
y += h;
|
||||
height += h + slotsMargin.Top;
|
||||
anyAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Update panel height
|
||||
if (anyAdded)
|
||||
y -= _itemsSpacing;
|
||||
if (anyAdded)
|
||||
y += slotsMargin.Bottom;
|
||||
float height = dropOffset + y;
|
||||
_cachedHeight = height;
|
||||
if (_animationProgress >= 1.0f && _isClosed)
|
||||
y = minHeight;
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace FlaxEngine.GUI
|
||||
private Color _scrollbarTrackColor;
|
||||
private Color _scrollbarThumbColor;
|
||||
private Color _scrollbarThumbSelectedColor;
|
||||
private Rectangle _controlsBoundsBeforeLayout;
|
||||
|
||||
/// <summary>
|
||||
/// The cached scroll area bounds. Used to scroll contents of the panel control. Cached during performing layout.
|
||||
@@ -530,8 +531,25 @@ namespace FlaxEngine.GUI
|
||||
{
|
||||
// Arrange controls and get scroll bounds
|
||||
ArrangeAndGetBounds();
|
||||
UpdateScrollBars();
|
||||
_controlsBoundsBeforeLayout = _controlsBounds;
|
||||
}
|
||||
|
||||
// Update scroll bars
|
||||
/// <inheritdoc />
|
||||
protected override void PerformLayoutAfterChildren()
|
||||
{
|
||||
// If controls area changed during layout then update scroll bars again
|
||||
ArrangeAndGetBounds();
|
||||
if (_controlsBoundsBeforeLayout != _controlsBounds)
|
||||
{
|
||||
UpdateScrollBars();
|
||||
}
|
||||
|
||||
base.PerformLayoutAfterChildren();
|
||||
}
|
||||
|
||||
private void UpdateScrollBars()
|
||||
{
|
||||
var controlsBounds = _controlsBounds;
|
||||
var scrollBounds = controlsBounds;
|
||||
_scrollMargin.ExpandRectangle(ref scrollBounds);
|
||||
|
||||
@@ -72,8 +72,11 @@ namespace FlaxEngine.GUI
|
||||
get => _slotSpacing;
|
||||
set
|
||||
{
|
||||
_slotSpacing = value;
|
||||
PerformLayout();
|
||||
if (!Float2.NearEqual(ref _slotSpacing, ref value))
|
||||
{
|
||||
_slotSpacing = value;
|
||||
PerformLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,11 +92,11 @@ namespace FlaxEngine.GUI
|
||||
/// Initializes a new instance of the <see cref="UniformGridPanel"/> class.
|
||||
/// </summary>
|
||||
/// <param name="slotPadding">The slot padding.</param>
|
||||
public UniformGridPanel(float slotPadding = 0)
|
||||
public UniformGridPanel(float slotPadding)
|
||||
{
|
||||
AutoFocus = false;
|
||||
SlotPadding = new Margin(slotPadding);
|
||||
SlotSpacing = new Float2(2);
|
||||
_slotPadding = new Margin(slotPadding);
|
||||
_slotSpacing = new Float2(2);
|
||||
_slotsH = _slotsV = 5;
|
||||
}
|
||||
|
||||
@@ -105,25 +108,32 @@ namespace FlaxEngine.GUI
|
||||
int slotsV = _slotsV;
|
||||
int slotsH = _slotsH;
|
||||
Float2 slotSize;
|
||||
Float2 size = Size;
|
||||
bool applySpacing = true;
|
||||
APPLY_SPACING:
|
||||
if (_slotsV + _slotsH == 0)
|
||||
{
|
||||
slotSize = HasChildren ? Children[0].Size : new Float2(32);
|
||||
slotsH = Mathf.CeilToInt(Width / slotSize.X);
|
||||
slotsV = Mathf.CeilToInt(Height / slotSize.Y);
|
||||
slotsH = Mathf.CeilToInt(size.X / slotSize.X);
|
||||
slotsV = Mathf.CeilToInt(size.Y / slotSize.Y);
|
||||
}
|
||||
else if (slotsH == 0)
|
||||
{
|
||||
float size = Height / slotsV;
|
||||
slotSize = new Float2(size);
|
||||
slotSize = new Float2(size.Y / slotsV);
|
||||
}
|
||||
else if (slotsV == 0)
|
||||
{
|
||||
float size = Width / slotsH;
|
||||
slotSize = new Float2(size);
|
||||
slotSize = new Float2(size.X / slotsH);
|
||||
}
|
||||
else
|
||||
{
|
||||
slotSize = new Float2(Width / slotsH, Height / slotsV);
|
||||
slotSize = new Float2(size.X / slotsH, size.Y / slotsV);
|
||||
}
|
||||
if (applySpacing && _slotSpacing != Float2.Zero)
|
||||
{
|
||||
applySpacing = false;
|
||||
size -= _slotSpacing * new Float2(slotsH > 1 ? slotsH - 1 : 0, slotsV > 1 ? slotsV - 1 : 0);
|
||||
goto APPLY_SPACING;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
@@ -135,45 +145,9 @@ namespace FlaxEngine.GUI
|
||||
|
||||
for (int x = 0; x < end; x++)
|
||||
{
|
||||
var slotBounds = new Rectangle(slotSize.X * x, slotSize.Y * y, slotSize.X, slotSize.Y);
|
||||
var slotBounds = new Rectangle((slotSize + _slotSpacing) * new Float2(x, y), slotSize);
|
||||
_slotPadding.ShrinkRectangle(ref slotBounds);
|
||||
|
||||
if (slotsV > 1)
|
||||
{
|
||||
if (y == 0)
|
||||
{
|
||||
slotBounds.Height -= _slotSpacing.Y * 0.5f;
|
||||
}
|
||||
else if (y == slotsV - 1)
|
||||
{
|
||||
slotBounds.Height -= _slotSpacing.Y * 0.5f;
|
||||
slotBounds.Y += _slotSpacing.Y * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
slotBounds.Height -= _slotSpacing.Y;
|
||||
slotBounds.Y += _slotSpacing.Y * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
if (slotsH > 1)
|
||||
{
|
||||
if (x == 0)
|
||||
{
|
||||
slotBounds.Width -= _slotSpacing.X * 0.5f;
|
||||
}
|
||||
else if (x == slotsH - 1)
|
||||
{
|
||||
slotBounds.Width -= _slotSpacing.X * 0.5f;
|
||||
slotBounds.X += _slotSpacing.X * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
slotBounds.Width -= _slotSpacing.X;
|
||||
slotBounds.X += _slotSpacing.X * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
var c = _children[i++];
|
||||
c.Bounds = slotBounds;
|
||||
}
|
||||
|
||||
@@ -372,8 +372,8 @@ void ShaderGenerator::ProcessGroupMath(Box* box, Node* node, Value& value)
|
||||
// Atan2
|
||||
case 41:
|
||||
{
|
||||
Value v1 = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
Value v2 = tryGetValue(node->GetBox(1), Value::Zero);
|
||||
Value v1 = tryGetValue(node->GetBox(0), 0, Value::Zero);
|
||||
Value v2 = tryGetValue(node->GetBox(1), 1, Value::Zero);
|
||||
value = writeFunction2(node, v1, v2, TEXT("atan2"));
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user