You're breathtaking!
This commit is contained in:
@@ -0,0 +1,957 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "VisjectGraph.h"
|
||||
#include "GraphUtilities.h"
|
||||
#include "Engine/Core/Random.h"
|
||||
#include "Engine/Core/Math/Vector4.h"
|
||||
#include "Engine/Core/Math/Transform.h"
|
||||
#include "Engine/Engine/GameplayGlobals.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Level/Actor.h"
|
||||
|
||||
#define RAND Random::Rand()
|
||||
|
||||
VisjectExecutor::VisjectExecutor()
|
||||
{
|
||||
// Register per group type processing events
|
||||
// Note: index must match group id
|
||||
#if BUILD_DEBUG
|
||||
Platform::MemoryClear(&_perGroupProcessCall, sizeof(_perGroupProcessCall));
|
||||
#endif
|
||||
_perGroupProcessCall[2] = &VisjectExecutor::ProcessGroupConstants;
|
||||
_perGroupProcessCall[3] = &VisjectExecutor::ProcessGroupMath;
|
||||
_perGroupProcessCall[4] = &VisjectExecutor::ProcessGroupPacking;
|
||||
_perGroupProcessCall[7] = &VisjectExecutor::ProcessGroupTools;
|
||||
_perGroupProcessCall[10] = &VisjectExecutor::ProcessGroupBoolean;
|
||||
_perGroupProcessCall[11] = &VisjectExecutor::ProcessGroupBitwise;
|
||||
_perGroupProcessCall[12] = &VisjectExecutor::ProcessGroupComparisons;
|
||||
_perGroupProcessCall[14] = &VisjectExecutor::ProcessGroupParticles;
|
||||
}
|
||||
|
||||
VisjectExecutor::~VisjectExecutor()
|
||||
{
|
||||
}
|
||||
|
||||
void VisjectExecutor::OnError(Node* node, Box* box, const StringView& message)
|
||||
{
|
||||
Error(node, box, message);
|
||||
}
|
||||
|
||||
void VisjectExecutor::ProcessGroupConstants(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// Constant value
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 12:
|
||||
value = node->Values[0];
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
const Value& cv = node->Values[0];
|
||||
if (box->ID == 0)
|
||||
value = cv;
|
||||
else if (box->ID == 1)
|
||||
value = cv.AsVector2().X;
|
||||
else if (box->ID == 2)
|
||||
value = cv.AsVector2().Y;
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
const Value& cv = node->Values[0];
|
||||
if (box->ID == 0)
|
||||
value = cv;
|
||||
else if (box->ID == 1)
|
||||
value = cv.AsVector3().X;
|
||||
else if (box->ID == 2)
|
||||
value = cv.AsVector3().Y;
|
||||
else if (box->ID == 3)
|
||||
value = cv.AsVector3().Z;
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
case 7:
|
||||
{
|
||||
const Value& cv = node->Values[0];
|
||||
if (box->ID == 0)
|
||||
value = cv;
|
||||
else if (box->ID == 1)
|
||||
value = cv.AsVector4().X;
|
||||
else if (box->ID == 2)
|
||||
value = cv.AsVector4().Y;
|
||||
else if (box->ID == 3)
|
||||
value = cv.AsVector4().Z;
|
||||
else if (box->ID == 4)
|
||||
value = cv.AsVector4().W;
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
const float pitch = (float)node->Values[0];
|
||||
const float yaw = (float)node->Values[1];
|
||||
const float roll = (float)node->Values[2];
|
||||
value = Quaternion::Euler(pitch, yaw, roll);
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
{
|
||||
value = node->Values[0];
|
||||
break;
|
||||
}
|
||||
// PI
|
||||
case 10:
|
||||
value = PI;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VisjectExecutor::ProcessGroupMath(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// Add, Subtract, Multiply, Divide, Modulo, Max, Min, Pow, Fmod, Atan2
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 21:
|
||||
case 22:
|
||||
case 23:
|
||||
case 40:
|
||||
case 41:
|
||||
{
|
||||
Value v1 = tryGetValue(node->GetBox(0), 0, Value::Zero);
|
||||
Value v2 = tryGetValue(node->GetBox(1), 1, Value::Zero).Cast(v1.Type);
|
||||
GraphUtilities::ApplySomeMathHere(node->TypeID, value, v1, v2);
|
||||
break;
|
||||
}
|
||||
// Absolute Value, Ceil, Cosine, Floor, Round, Saturate, Sine, Sqrt, Tangent, Negate, 1 - Value, Asine, Acosine, Atan, Trunc, Frac, Degrees, Radians
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
case 27:
|
||||
case 28:
|
||||
case 33:
|
||||
case 34:
|
||||
case 35:
|
||||
case 38:
|
||||
case 39:
|
||||
case 43:
|
||||
case 44:
|
||||
{
|
||||
Value v1 = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
GraphUtilities::ApplySomeMathHere(node->TypeID, value, v1);
|
||||
break;
|
||||
}
|
||||
// Length, Normalize
|
||||
case 11:
|
||||
case 12:
|
||||
{
|
||||
Value v1 = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
switch (node->TypeID)
|
||||
{
|
||||
case 11:
|
||||
{
|
||||
switch (v1.Type.Type)
|
||||
{
|
||||
case VariantType::Vector2:
|
||||
value = v1.AsVector2().Length();
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
value = v1.AsVector3().Length();
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
value = Vector3(v1.AsVector4()).Length();
|
||||
break;
|
||||
default: CRASH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case 12:
|
||||
switch (v1.Type.Type)
|
||||
{
|
||||
case VariantType::Int:
|
||||
value = Math::Saturate(v1.AsInt);
|
||||
break;
|
||||
case VariantType::Uint:
|
||||
value = Math::Saturate(v1.AsUint);
|
||||
break;
|
||||
case VariantType::Float:
|
||||
value = Math::Saturate(v1.AsFloat);
|
||||
break;
|
||||
case VariantType::Vector2:
|
||||
value = Vector2::Normalize(v1.AsVector2());
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
value = Vector3::Normalize(v1.AsVector3());
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
value = Vector4(Vector3::Normalize(Vector3(v1.AsVector4())), 0.0f);
|
||||
break;
|
||||
default: CRASH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Cross, Distance, Dot
|
||||
case 18:
|
||||
case 19:
|
||||
case 20:
|
||||
{
|
||||
Value v1 = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
Value v2 = tryGetValue(node->GetBox(1), Value::Zero).Cast(v1.Type);
|
||||
switch (node->TypeID)
|
||||
{
|
||||
case 18:
|
||||
switch (v1.Type.Type)
|
||||
{
|
||||
case VariantType::Vector3:
|
||||
value = Vector3::Cross(v1.AsVector3(), v2.AsVector3());
|
||||
break;
|
||||
default: CRASH;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 19:
|
||||
switch (v1.Type.Type)
|
||||
{
|
||||
case VariantType::Vector2:
|
||||
value = Vector2::Distance(v1.AsVector2(), v2.AsVector2());
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
value = Vector3::Distance(v1.AsVector3(), v2.AsVector3());
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
case VariantType::Color:
|
||||
value = Vector3::Distance((Vector3)v1, (Vector3)v2);
|
||||
break;
|
||||
default: CRASH;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 20:
|
||||
switch (v1.Type.Type)
|
||||
{
|
||||
case VariantType::Vector2:
|
||||
value = Vector2::Dot(v1.AsVector2(), v2.AsVector2());
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
value = Vector3::Dot(v1.AsVector3(), v2.AsVector3());
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
case VariantType::Color:
|
||||
value = Vector3::Dot((Vector3)v1, (Vector3)v2);
|
||||
break;
|
||||
default: CRASH;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Clamp
|
||||
case 24:
|
||||
{
|
||||
Value v1 = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
Value v2 = tryGetValue(node->GetBox(1), 0, Value::Zero).Cast(v1.Type);
|
||||
Value v3 = tryGetValue(node->GetBox(2), 1, Value::One).Cast(v1.Type);
|
||||
GraphUtilities::ApplySomeMathHere(value, v1, v2, v3, [](float a, float b, float c)
|
||||
{
|
||||
return Math::Clamp(a, b, c);
|
||||
});
|
||||
break;
|
||||
}
|
||||
// Lerp
|
||||
case 25:
|
||||
{
|
||||
Value a = tryGetValue(node->GetBox(0), 0, Value::Zero);
|
||||
Value b = tryGetValue(node->GetBox(1), 1, Value::One).Cast(a.Type);
|
||||
Value alpha = tryGetValue(node->GetBox(2), 2, Value::Zero).Cast(ValueType(ValueType::Float));
|
||||
value = Value::Lerp(a, b, alpha.AsFloat);
|
||||
break;
|
||||
}
|
||||
// Reflect
|
||||
case 26:
|
||||
{
|
||||
Value v1 = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
Value v2 = tryGetValue(node->GetBox(1), Value::Zero).Cast(v1.Type);
|
||||
switch (v1.Type.Type)
|
||||
{
|
||||
case VariantType::Vector2:
|
||||
value = v1.AsVector2() - 2 * v2.AsVector2() * Vector2::Dot(v1.AsVector2(), v2.AsVector2());
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
value = v1.AsVector3() - 2 * v2.AsVector3() * Vector3::Dot(v1.AsVector3(), v2.AsVector3());
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
value = Vector4(v1.AsVector4() - 2 * v2.AsVector4() * Vector3::Dot((Vector3)v1, (Vector3)v2));
|
||||
break;
|
||||
default: CRASH;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Mad
|
||||
case 31:
|
||||
{
|
||||
Value v1 = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
Value v2 = tryGetValue(node->GetBox(1), 0, Value::One).Cast(v1.Type);
|
||||
Value v3 = tryGetValue(node->GetBox(2), 1, Value::Zero).Cast(v1.Type);
|
||||
GraphUtilities::ApplySomeMathHere(value, v1, v2, v3, [](float a, float b, float c)
|
||||
{
|
||||
return (a * b) + c;
|
||||
});
|
||||
break;
|
||||
}
|
||||
// Extract Largest Component
|
||||
case 32:
|
||||
{
|
||||
const auto v1 = (Vector3)tryGetValue(node->GetBox(0), Value::Zero);
|
||||
value = Math::ExtractLargestComponent(v1);
|
||||
break;
|
||||
}
|
||||
// Bias and Scale
|
||||
case 36:
|
||||
{
|
||||
ASSERT(node->Values.Count() == 2 && node->Values[0].Type == VariantType::Float && node->Values[1].Type == VariantType::Float);
|
||||
const auto bias = node->Values[0].AsFloat;
|
||||
const auto scale = node->Values[1].AsFloat;
|
||||
const auto input = (Vector3)tryGetValue(node->GetBox(0), Value::Zero);
|
||||
value = (input + bias) * scale;
|
||||
break;
|
||||
}
|
||||
// Rotate About Axis
|
||||
case 37:
|
||||
{
|
||||
const auto normalizedRotationAxis = (Vector3)tryGetValue(node->GetBox(0), Value::Zero);
|
||||
const auto rotationAngle = (float)tryGetValue(node->GetBox(1), Value::Zero);
|
||||
const auto pivotPoint = (Vector3)tryGetValue(node->GetBox(2), Value::Zero);
|
||||
const auto position = (Vector3)tryGetValue(node->GetBox(3), Value::Zero);
|
||||
value = Math::RotateAboutAxis(normalizedRotationAxis, rotationAngle, pivotPoint, position);
|
||||
break;
|
||||
}
|
||||
// Near Equal
|
||||
case 42:
|
||||
{
|
||||
const Value a = tryGetValue(node->GetBox(0), node->Values[0]);
|
||||
const Value b = tryGetValue(node->GetBox(1), node->Values[1]).Cast(a.Type);
|
||||
const float epsilon = (float)tryGetValue(node->GetBox(2), node->Values[2]);
|
||||
value = Value::NearEqual(a, b, epsilon);
|
||||
break;
|
||||
}
|
||||
// Enum Value
|
||||
case 45:
|
||||
value = (uint64)tryGetValue(node->GetBox(0), Value::Zero);
|
||||
break;
|
||||
// Enum AND
|
||||
case 46:
|
||||
value = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
if (value.Type.Type == VariantType::Enum)
|
||||
value.AsUint64 = value.AsUint64 & (uint64)tryGetValue(node->GetBox(1), Value::Zero);
|
||||
break;
|
||||
// Enum OR
|
||||
case 47:
|
||||
value = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
if (value.Type.Type == VariantType::Enum)
|
||||
value.AsUint64 = value.AsUint64 | (uint64)tryGetValue(node->GetBox(1), Value::Zero);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VisjectExecutor::ProcessGroupPacking(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// Pack
|
||||
case 20:
|
||||
{
|
||||
float vX = (float)tryGetValue(node->GetBox(1), node->Values[0]);
|
||||
float vY = (float)tryGetValue(node->GetBox(2), node->Values[1]);
|
||||
value = Vector2(vX, vY);
|
||||
break;
|
||||
}
|
||||
case 21:
|
||||
{
|
||||
float vX = (float)tryGetValue(node->GetBox(1), node->Values[0]);
|
||||
float vY = (float)tryGetValue(node->GetBox(2), node->Values[1]);
|
||||
float vZ = (float)tryGetValue(node->GetBox(3), node->Values[2]);
|
||||
value = Vector3(vX, vY, vZ);
|
||||
break;
|
||||
}
|
||||
case 22:
|
||||
{
|
||||
float vX = (float)tryGetValue(node->GetBox(1), node->Values[0]);
|
||||
float vY = (float)tryGetValue(node->GetBox(2), node->Values[1]);
|
||||
float vZ = (float)tryGetValue(node->GetBox(3), node->Values[2]);
|
||||
float vW = (float)tryGetValue(node->GetBox(4), node->Values[3]);
|
||||
value = Vector4(vX, vY, vZ, vW);
|
||||
break;
|
||||
}
|
||||
case 23:
|
||||
{
|
||||
float vX = (float)tryGetValue(node->GetBox(1), node->Values[0]);
|
||||
float vY = (float)tryGetValue(node->GetBox(2), node->Values[1]);
|
||||
float vZ = (float)tryGetValue(node->GetBox(3), node->Values[2]);
|
||||
value = Quaternion::Euler(vX, vY, vZ);
|
||||
break;
|
||||
}
|
||||
case 24:
|
||||
{
|
||||
const Vector3 vX = (Vector3)tryGetValue(node->GetBox(1), Vector3::Zero);
|
||||
const Quaternion vY = (Quaternion)tryGetValue(node->GetBox(2), Quaternion::Identity);
|
||||
const Vector3 vZ = (Vector3)tryGetValue(node->GetBox(3), Vector3::One);
|
||||
value = Variant(Transform(vX, vY, vZ));
|
||||
break;
|
||||
}
|
||||
case 25:
|
||||
{
|
||||
const Vector3 vX = (Vector3)tryGetValue(node->GetBox(1), Vector3::Zero);
|
||||
const Vector3 vY = (Vector3)tryGetValue(node->GetBox(2), Vector3::Zero);
|
||||
value = Variant(BoundingBox(vX, vY));
|
||||
break;
|
||||
}
|
||||
// Unpack
|
||||
case 30:
|
||||
{
|
||||
Vector2 v = (Vector2)tryGetValue(node->GetBox(0), Vector2::Zero);
|
||||
int32 subIndex = box->ID - 1;
|
||||
ASSERT(subIndex >= 0 && subIndex < 2);
|
||||
value = v.Raw[subIndex];
|
||||
break;
|
||||
}
|
||||
case 31:
|
||||
{
|
||||
Vector3 v = (Vector3)tryGetValue(node->GetBox(0), Vector3::Zero);
|
||||
int32 subIndex = box->ID - 1;
|
||||
ASSERT(subIndex >= 0 && subIndex < 3);
|
||||
value = v.Raw[subIndex];
|
||||
break;
|
||||
}
|
||||
case 32:
|
||||
{
|
||||
Vector4 v = (Vector4)tryGetValue(node->GetBox(0), Vector4::Zero);
|
||||
int32 subIndex = box->ID - 1;
|
||||
ASSERT(subIndex >= 0 && subIndex < 4);
|
||||
value = v.Raw[subIndex];
|
||||
break;
|
||||
}
|
||||
case 33:
|
||||
{
|
||||
const Vector3 v = ((Quaternion)tryGetValue(node->GetBox(0), Quaternion::Identity)).GetEuler();
|
||||
const int32 subIndex = box->ID - 1;
|
||||
ASSERT(subIndex >= 0 && subIndex < 3);
|
||||
value = v.Raw[subIndex];
|
||||
break;
|
||||
}
|
||||
case 34:
|
||||
{
|
||||
const Transform v = (Transform)tryGetValue(node->GetBox(0), Variant::Zero);
|
||||
switch (box->ID)
|
||||
{
|
||||
case 1:
|
||||
value = v.Translation;
|
||||
break;
|
||||
case 2:
|
||||
value = v.Orientation;
|
||||
break;
|
||||
case 3:
|
||||
value = v.Scale;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 35:
|
||||
{
|
||||
const BoundingBox v = (BoundingBox)tryGetValue(node->GetBox(0), Variant::Zero);
|
||||
switch (box->ID)
|
||||
{
|
||||
case 1:
|
||||
value = v.Minimum;
|
||||
break;
|
||||
case 2:
|
||||
value = v.Maximum;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Mask X, Y, Z, W
|
||||
case 40:
|
||||
case 41:
|
||||
case 42:
|
||||
case 43:
|
||||
{
|
||||
const Vector4 v = (Vector4)tryGetValue(node->GetBox(0), Vector4::Zero);
|
||||
value = v.Raw[node->TypeID - 40];
|
||||
break;
|
||||
}
|
||||
// Mask XY, YZ, XZ,...
|
||||
case 44:
|
||||
{
|
||||
value = (Vector2)tryGetValue(node->GetBox(0), Vector2::Zero);
|
||||
break;
|
||||
}
|
||||
case 45:
|
||||
{
|
||||
const Vector4 v = (Vector4)tryGetValue(node->GetBox(0), Vector4::Zero);
|
||||
value = Vector2(v.X, v.Z);
|
||||
break;
|
||||
}
|
||||
case 46:
|
||||
{
|
||||
const Vector4 v = (Vector4)tryGetValue(node->GetBox(0), Vector4::Zero);
|
||||
value = Vector2(v.Y, v.Z);
|
||||
break;
|
||||
}
|
||||
// Mask XYZ
|
||||
case 70:
|
||||
{
|
||||
value = (Vector3)tryGetValue(node->GetBox(0), Vector3::Zero);
|
||||
break;
|
||||
}
|
||||
// Append
|
||||
case 100:
|
||||
{
|
||||
auto in0 = node->GetBox(0);
|
||||
auto in1 = node->GetBox(1);
|
||||
if (!in0->HasConnection() || !in1->HasConnection())
|
||||
{
|
||||
value = Value::Zero;
|
||||
break;
|
||||
}
|
||||
|
||||
auto value0 = eatBox(in0->GetParent<Node>(), in0->FirstConnection());
|
||||
auto value1 = eatBox(in1->GetParent<Node>(), in1->FirstConnection());
|
||||
|
||||
auto count0 = GraphUtilities::CountComponents(value0.Type.Type);
|
||||
auto count1 = GraphUtilities::CountComponents(value1.Type.Type);
|
||||
|
||||
auto count = count0 + count1;
|
||||
switch (count)
|
||||
{
|
||||
case 1:
|
||||
value = count0 ? value0 : value1;
|
||||
break;
|
||||
case 2:
|
||||
value = Vector2((float)value0, (float)value1);
|
||||
break;
|
||||
case 3:
|
||||
if (count0 == 1)
|
||||
value = Vector3((float)value0, value1.AsVector2().X, value1.AsVector2().Y);
|
||||
else
|
||||
value = Vector3((Vector2)value0, (float)value1);
|
||||
break;
|
||||
case 4:
|
||||
if (count0 == 1)
|
||||
value = Vector4((float)value0, value1.AsVector3().X, value1.AsVector3().Y, value1.AsVector3().Z);
|
||||
else if (count0 == 2)
|
||||
value = Vector4(value0.AsVector2().X, value0.AsVector2().Y, value1.AsVector2().X, value1.AsVector2().Y);
|
||||
else
|
||||
value = Vector4((Vector3)value0, (float)value1);
|
||||
break;
|
||||
default:
|
||||
value = Value::Zero;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VisjectExecutor::ProcessGroupTools(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// Color Gradient
|
||||
case 10:
|
||||
{
|
||||
float time, prevTime, curTime;
|
||||
Color prevColor, curColor;
|
||||
const int32 count = (int32)node->Values[0];
|
||||
switch (count)
|
||||
{
|
||||
case 0:
|
||||
// No sample
|
||||
value = Value::Zero;
|
||||
break;
|
||||
case 1:
|
||||
// Single sample
|
||||
value = (Color)node->Values[2];
|
||||
break;
|
||||
case 2:
|
||||
// Linear blend between 2 samples
|
||||
time = (float)tryGetValue(node->GetBox(0), Value::Zero);
|
||||
prevTime = (float)node->Values[1];
|
||||
prevColor = (Color)node->Values[2];
|
||||
curTime = (float)node->Values[3];
|
||||
curColor = (Color)node->Values[4];
|
||||
value = Color::Lerp(prevColor, curColor, Math::Saturate((time - prevTime) / (curTime - prevTime)));
|
||||
break;
|
||||
default:
|
||||
time = (float)tryGetValue(node->GetBox(0), Value::Zero);
|
||||
if (time >= node->Values[1 + count * 2 - 2].AsFloat)
|
||||
{
|
||||
// Outside the range
|
||||
value = (Color)node->Values[1 + count * 2 - 2 + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find 2 samples to blend between them
|
||||
prevTime = (float)node->Values[1];
|
||||
prevColor = (Color)node->Values[2];
|
||||
for (int32 i = 1; i < count; i++)
|
||||
{
|
||||
curTime = (float)node->Values[i * 2 + 1];
|
||||
curColor = (Color)node->Values[i * 2 + 2];
|
||||
|
||||
if (time <= curTime)
|
||||
{
|
||||
value = Color::Lerp(prevColor, curColor, Math::Saturate((time - prevTime) / (curTime - prevTime)));
|
||||
break;
|
||||
}
|
||||
|
||||
prevTime = curTime;
|
||||
prevColor = curColor;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Curve
|
||||
#define SAMPLE_CURVE(id, curves, type, graphType) \
|
||||
case id: \
|
||||
{ \
|
||||
const auto& curve = GetCurrentGraph()->curves[node->Data.Curve.CurveIndex]; \
|
||||
const float time = (float)tryGetValue(node->GetBox(0), Value::Zero); \
|
||||
value.Type = VariantType(VariantType::graphType); \
|
||||
curve.Evaluate(*(type*)value.AsData, time, false); \
|
||||
break; \
|
||||
}
|
||||
SAMPLE_CURVE(12, FloatCurves, float, Float)
|
||||
SAMPLE_CURVE(13, Vector2Curves, Vector2, Vector2)
|
||||
SAMPLE_CURVE(14, Vector3Curves, Vector3, Vector3)
|
||||
SAMPLE_CURVE(15, Vector4Curves, Vector4, Vector4)
|
||||
#undef SETUP_CURVE
|
||||
// Get Gameplay Global
|
||||
case 16:
|
||||
{
|
||||
const auto asset = node->Assets[0].As<GameplayGlobals>();
|
||||
if (asset)
|
||||
{
|
||||
const StringView& name = (StringView)node->Values[1];
|
||||
const auto e = asset->Variables.Find(name);
|
||||
value = e != asset->Variables.End() ? e->Value.Value : Value::Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = Value::Zero;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Platform Switch
|
||||
case 17:
|
||||
{
|
||||
int32 boxId = 1;
|
||||
switch (PLATFORM_TYPE)
|
||||
{
|
||||
case PlatformType::Windows:
|
||||
boxId = 2;
|
||||
break;
|
||||
case PlatformType::XboxOne:
|
||||
boxId = 3;
|
||||
break;
|
||||
case PlatformType::UWP:
|
||||
boxId = 4;
|
||||
break;
|
||||
case PlatformType::Linux:
|
||||
boxId = 5;
|
||||
break;
|
||||
case PlatformType::PS4:
|
||||
boxId = 6;
|
||||
break;
|
||||
case PlatformType::XboxScarlett:
|
||||
boxId = 7;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
value = tryGetValue(node->GetBox(node->GetBox(boxId)->HasConnection() ? boxId : 1), Value::Zero);
|
||||
break;
|
||||
}
|
||||
// Asset Reference
|
||||
case 18:
|
||||
{
|
||||
value = Content::LoadAsync<Asset>((Guid)node->Values[0]);
|
||||
break;
|
||||
}
|
||||
// To String
|
||||
case 20:
|
||||
{
|
||||
value.SetString(tryGetValue(node->GetBox(1), Value(StringView::Empty)).ToString());
|
||||
break;
|
||||
}
|
||||
// Actor Reference
|
||||
case 21:
|
||||
{
|
||||
value = Scripting::FindObject<Actor>((Guid)node->Values[0]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VisjectExecutor::ProcessGroupBoolean(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// NOT
|
||||
case 1:
|
||||
{
|
||||
const bool a = (bool)tryGetValue(node->GetBox(0), Value::False);
|
||||
value = !a;
|
||||
break;
|
||||
}
|
||||
// AND, OR, XOR, NOR, NAND
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
{
|
||||
const bool a = (bool)tryGetValue(node->GetBox(0), 0, node->Values[0]);
|
||||
const bool b = (bool)tryGetValue(node->GetBox(1), 1, node->Values[1]);
|
||||
bool result = false;
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// AND
|
||||
case 2:
|
||||
result = a && b;
|
||||
break;
|
||||
// OR
|
||||
case 3:
|
||||
result = a || b;
|
||||
break;
|
||||
// XOR
|
||||
case 4:
|
||||
result = !a != !b;
|
||||
break;
|
||||
// NOR
|
||||
case 5:
|
||||
result = !(a || b);
|
||||
break;
|
||||
// NAND
|
||||
case 6:
|
||||
result = !(a && b);
|
||||
break;
|
||||
}
|
||||
value = result;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VisjectExecutor::ProcessGroupBitwise(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// NOT
|
||||
case 1:
|
||||
{
|
||||
const int32 a = (int32)tryGetValue(node->GetBox(0), Value(0));
|
||||
value = !a;
|
||||
break;
|
||||
}
|
||||
// AND, OR, XOR
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
{
|
||||
const int32 a = (int32)tryGetValue(node->GetBox(0), 0, node->Values[0]);
|
||||
const int32 b = (int32)tryGetValue(node->GetBox(1), 1, node->Values[1]);
|
||||
int32 result = 0;
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// AND
|
||||
case 2:
|
||||
result = a & b;
|
||||
break;
|
||||
// OR
|
||||
case 3:
|
||||
result = a | b;
|
||||
break;
|
||||
// XOR
|
||||
case 4:
|
||||
result = a ^ b;
|
||||
break;
|
||||
}
|
||||
value = result;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VisjectExecutor::ProcessGroupComparisons(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// ==, !=, >, <=, >=
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
{
|
||||
const Value a = tryGetValue(node->GetBox(0), 0, node->Values[0]);
|
||||
const Value b = tryGetValue(node->GetBox(1), 1, node->Values[1]).Cast(a.Type);
|
||||
bool result = false;
|
||||
switch (node->TypeID)
|
||||
{
|
||||
case 1:
|
||||
result = a == b;
|
||||
break;
|
||||
case 2:
|
||||
result = a != b;
|
||||
break;
|
||||
case 3:
|
||||
result = a > b;
|
||||
break;
|
||||
case 4:
|
||||
result = a < b;
|
||||
break;
|
||||
case 5:
|
||||
result = a <= b;
|
||||
break;
|
||||
case 6:
|
||||
result = a >= b;
|
||||
break;
|
||||
}
|
||||
value = result;
|
||||
break;
|
||||
}
|
||||
// Switch On Bool
|
||||
case 7:
|
||||
{
|
||||
const Value condition = tryGetValue(node->GetBox(0), Value::False);
|
||||
if (condition)
|
||||
value = tryGetValue(node->GetBox(2), 1, Value::Zero);
|
||||
else
|
||||
value = tryGetValue(node->GetBox(1), 0, Value::Zero);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VisjectExecutor::ProcessGroupParticles(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// Random Float
|
||||
case 208:
|
||||
{
|
||||
value = RAND;
|
||||
break;
|
||||
}
|
||||
// Random Vector2
|
||||
case 209:
|
||||
{
|
||||
value = Vector2(RAND, RAND);
|
||||
break;
|
||||
}
|
||||
// Random Vector3
|
||||
case 210:
|
||||
{
|
||||
value = Vector3(RAND, RAND, RAND);
|
||||
break;
|
||||
}
|
||||
// Random Vector4
|
||||
case 211:
|
||||
{
|
||||
value = Vector4(RAND, RAND, RAND, RAND);
|
||||
break;
|
||||
}
|
||||
// Random Float Range
|
||||
case 213:
|
||||
{
|
||||
auto& a = node->Values[0].AsFloat;
|
||||
auto& b = node->Values[1].AsFloat;
|
||||
value = Math::Lerp(a, b, RAND);
|
||||
break;
|
||||
}
|
||||
// Random Vector2 Range
|
||||
case 214:
|
||||
{
|
||||
auto a = (Vector2)node->Values[0];
|
||||
auto b = (Vector2)node->Values[1];
|
||||
value = Vector2(
|
||||
Math::Lerp(a.X, b.X, RAND),
|
||||
Math::Lerp(a.Y, b.Y, RAND)
|
||||
);
|
||||
break;
|
||||
}
|
||||
// Random Vector3 Range
|
||||
case 215:
|
||||
{
|
||||
auto a = (Vector3)node->Values[0];
|
||||
auto b = (Vector3)node->Values[1];
|
||||
value = Vector3(
|
||||
Math::Lerp(a.X, b.X, RAND),
|
||||
Math::Lerp(a.Y, b.Y, RAND),
|
||||
Math::Lerp(a.Z, b.Z, RAND)
|
||||
);
|
||||
break;
|
||||
}
|
||||
// Random Vector4 Range
|
||||
case 216:
|
||||
{
|
||||
auto a = (Vector4)node->Values[0];
|
||||
auto b = (Vector4)node->Values[1];
|
||||
value = Vector4(
|
||||
Math::Lerp(a.X, b.X, RAND),
|
||||
Math::Lerp(a.Y, b.Y, RAND),
|
||||
Math::Lerp(a.Z, b.Z, RAND),
|
||||
Math::Lerp(a.W, b.W, RAND)
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VisjectExecutor::Value VisjectExecutor::tryGetValue(Box* box, int32 defaultValueBoxIndex, const Value& defaultValue)
|
||||
{
|
||||
const auto parentNode = box->GetParent<Node>();
|
||||
if (box->HasConnection())
|
||||
return eatBox(parentNode, box->FirstConnection());
|
||||
if (parentNode->Values.Count() > defaultValueBoxIndex)
|
||||
return Value(parentNode->Values[defaultValueBoxIndex]);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
VisjectExecutor::Value VisjectExecutor::tryGetValue(Box* box, const Value& defaultValue)
|
||||
{
|
||||
return box && box->HasConnection() ? eatBox(box->GetParent<Node>(), box->FirstConnection()) : defaultValue;
|
||||
}
|
||||
Reference in New Issue
Block a user