Skip to content

Commit

Permalink
Initial implementation of Quaternion type in ZScript
Browse files Browse the repository at this point in the history
  • Loading branch information
MrRaveYard authored and coelckers committed Nov 13, 2022
1 parent f41f393 commit 31ac1bd
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 21 deletions.
2 changes: 2 additions & 0 deletions src/common/engine/namedef.h
Expand Up @@ -125,9 +125,11 @@ xx(Fixed)
xx(Vector2)
xx(Vector3)
xx(Vector4)
xx(Quat)
xx(FVector2)
xx(FVector3)
xx(FVector4)
xx(FQuat)
xx(let)

xx(Min)
Expand Down
121 changes: 105 additions & 16 deletions src/common/scripting/backend/codegen.cpp
Expand Up @@ -809,6 +809,34 @@ ExpEmit FxVectorValue::Emit(VMFunctionBuilder *build)
return out;
}

//==========================================================================
//
//
//
//==========================================================================

FxQuaternionValue::FxQuaternionValue(FxExpression* x, FxExpression* y, FxExpression* z, FxExpression* w, const FScriptPosition& sc) : FxVectorValue(x, y, z, w, sc)
{
}

FxExpression* FxQuaternionValue::Resolve(FCompileContext& ctx)
{
auto base = FxVectorValue::Resolve(ctx);
if (base)
{
if (base->ValueType->GetRegCount() != 4)
{
ScriptPosition.Message(MSG_ERROR, "Quat expression requires 4 arguments, got %d instead", base->ValueType->GetRegCount());
delete base;
return nullptr;
}

base->ValueType = TypeQuaternion;
}
return base;
}


//==========================================================================
//
//
Expand Down Expand Up @@ -1727,7 +1755,7 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx)
delete this;
return x;
}
else if ((basex->IsVector2() && IsVector2()) || (basex->IsVector3() && IsVector3()) || (basex->IsVector4() && IsVector4()))
else if ((basex->IsVector2() && IsVector2()) || (basex->IsVector3() && IsVector3()) || (basex->IsVector4() && IsVector4()) || (basex->IsQuaternion() && IsQuaternion()))
{
auto x = basex;
basex = nullptr;
Expand Down Expand Up @@ -1799,7 +1827,7 @@ FxExpression *FxPlusSign::Resolve(FCompileContext& ctx)
CHECKRESOLVED();
SAFE_RESOLVE(Operand, ctx);

if (Operand->IsNumeric() || Operand->IsVector())
if (Operand->IsNumeric() || Operand->IsVector() || Operand->IsQuaternion())
{
FxExpression *e = Operand;
Operand = nullptr;
Expand Down Expand Up @@ -1853,7 +1881,7 @@ FxExpression *FxMinusSign::Resolve(FCompileContext& ctx)
CHECKRESOLVED();
SAFE_RESOLVE(Operand, ctx);

if (Operand->IsNumeric() || Operand->IsVector())
if (Operand->IsNumeric() || Operand->IsVector() || Operand->IsQuaternion())
{
if (Operand->isConstant())
{
Expand Down Expand Up @@ -2441,7 +2469,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
delete this;
return nullptr;
}
if (!Base->IsVector() && Base->ValueType->isStruct())
if (!Base->IsVector() && !Base->IsQuaternion() && Base->ValueType->isStruct())
{
ScriptPosition.Message(MSG_ERROR, "Struct assignment not implemented yet");
delete this;
Expand Down Expand Up @@ -2839,6 +2867,10 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx)
{
ValueType = TypeTextureID;
}
else if (left->IsQuaternion() && right->IsQuaternion())
{
ValueType = left->ValueType;
}
else if (left->IsVector() && right->IsVector())
{
// a vector2 can be added to or subtracted from a vector 3 but it needs to be the right operand.
Expand Down Expand Up @@ -2944,6 +2976,13 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
}
return to;
}
else if (IsQuaternion())
{
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
assert(op1.RegCount == 4 && op2.RegCount == 4);
build->Emit(OP_ADDV4_RR, to.RegNum, op1.RegNum, op2.RegNum);
return to;
}
else if (ValueType->GetRegType() == REGT_FLOAT)
{
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
Expand Down Expand Up @@ -2972,6 +3011,13 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
build->Emit(right->IsVector4() ? OP_SUBV4_RR : right->IsVector3() ? OP_SUBV3_RR : OP_SUBV2_RR, to.RegNum, op1.RegNum, op2.RegNum);
return to;
}
else if (IsQuaternion())
{
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
assert(op1.RegCount == 4 && op2.RegCount == 4);
build->Emit(OP_SUBV4_RR, to.RegNum, op1.RegNum, op2.RegNum);
return to;
}
else if (ValueType->GetRegType() == REGT_FLOAT)
{
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
Expand Down Expand Up @@ -3037,7 +3083,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx)
return nullptr;
}

if (left->IsVector() || right->IsVector())
if (left->IsVector() || right->IsVector() || left->IsQuaternion() || right->IsQuaternion())
{
switch (Operator)
{
Expand All @@ -3047,7 +3093,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx)
[[fallthrough]];

case '*':
if (left->IsVector() && right->IsNumeric())
if ((left->IsVector() || left->IsQuaternion()) && right->IsNumeric())
{
if (right->IsInteger())
{
Expand All @@ -3062,7 +3108,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx)
ValueType = left->ValueType;
break;
}
else if (right->IsVector() && left->IsNumeric())
else if ((right->IsVector() || right->IsQuaternion()) && left->IsNumeric())
{
if (left->IsInteger())
{
Expand Down Expand Up @@ -3162,7 +3208,7 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build)
ExpEmit op1 = left->Emit(build);
ExpEmit op2 = right->Emit(build);

if (IsVector())
if (IsVector() || IsQuaternion())
{
assert(Operator != '%');
if (right->IsVector())
Expand Down Expand Up @@ -3641,7 +3687,7 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx)
}

// identical types are always comparable, if they can be placed in a register, so we can save most checks if this is the case.
if (left->ValueType != right->ValueType && !(left->IsVector2() && right->IsVector2()) && !(left->IsVector3() && right->IsVector3()) && !(left->IsVector4() && right->IsVector4()))
if (left->ValueType != right->ValueType && !(left->IsVector2() && right->IsVector2()) && !(left->IsVector3() && right->IsVector3()) && !(left->IsVector4() && right->IsVector4()) && !(left->IsQuaternion() && right->IsQuaternion()))
{
FxExpression *x;
if (left->IsNumeric() && right->ValueType == TypeString && (x = StringConstToChar(right)))
Expand Down Expand Up @@ -7139,7 +7185,7 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx)
classx = nullptr;
return x;
}
else if (classx->ExprType == EFX_LocalVariable && classx->IsVector()) // vectors are a special case because they are held in registers
else if (classx->ExprType == EFX_LocalVariable && (classx->IsVector() || classx->IsQuaternion())) // vectors are a special case because they are held in registers
{
// since this is a vector, all potential things that may get here are single float or an xy-vector.
auto locvar = static_cast<FxLocalVariable *>(classx);
Expand Down Expand Up @@ -8058,6 +8104,25 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
}
break;

case NAME_FQuat:
case NAME_Quat:
if (CheckArgSize(MethodName, ArgList, 1, 4, ScriptPosition))
{
// Reuse vector expression
func = new FxQuaternionValue(
ArgList[0],
ArgList.Size() >= 2 ? ArgList[1] : nullptr,
ArgList.Size() >= 3 ? ArgList[2] : nullptr,
ArgList.Size() >= 4 ? ArgList[3] : nullptr,
ScriptPosition
);
ArgList.Clear();

delete this;
auto vector = func->Resolve(ctx);
return vector;
}
break;

default:
ScriptPosition.Message(MSG_ERROR, "Call to unknown function '%s'", MethodName.GetChars());
Expand Down Expand Up @@ -8301,6 +8366,24 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
return x->Resolve(ctx);
}
}
else if (Self->IsQuaternion())
{
// Reuse vector built-ins for quaternion
if (MethodName == NAME_Length || MethodName == NAME_LengthSquared || MethodName == NAME_Unit)
{
if (ArgList.Size() > 0)
{
ScriptPosition.Message(MSG_ERROR, "Too many parameters in call to %s", MethodName.GetChars());
delete this;
return nullptr;
}
auto x = new FxVectorBuiltin(Self, MethodName);
Self = nullptr;
delete this;
return x->Resolve(ctx);
}
}


else if (Self->ValueType == TypeString)
{
Expand Down Expand Up @@ -9275,12 +9358,13 @@ FxVectorBuiltin::~FxVectorBuiltin()
FxExpression *FxVectorBuiltin::Resolve(FCompileContext &ctx)
{
SAFE_RESOLVE(Self, ctx);
assert(Self->IsVector()); // should never be created for anything else.
assert(Self->IsVector() || Self->IsQuaternion()); // should never be created for anything else.
switch (Function.GetIndex())
{
case NAME_Angle:
assert(Self->IsVector());
case NAME_Length:
case NAME_LengthSquared:
case NAME_Angle:
ValueType = TypeFloat64;
break;

Expand Down Expand Up @@ -10673,7 +10757,7 @@ FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx)
else if (retCount == 1)
{
// If we already know the real return type we need at least try to cast the value to its proper type (unless in an anonymous function.)
if (hasProto && protoRetCount > 0 && ctx.Function->SymbolName != NAME_None)
if (hasProto && protoRetCount > 0 && ctx.Function->SymbolName != NAME_None && Args[0]->ValueType != ctx.ReturnProto->ReturnTypes[0])
{
Args[0] = new FxTypeCast(Args[0], ctx.ReturnProto->ReturnTypes[0], false, false);
Args[0] = Args[0]->Resolve(ctx);
Expand All @@ -10683,11 +10767,15 @@ FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx)
}
else
{
assert(ctx.ReturnProto != nullptr);
for (unsigned i = 0; i < retCount; i++)
{
Args[i] = new FxTypeCast(Args[i], ctx.ReturnProto->ReturnTypes[i], false, false);
Args[i] = Args[i]->Resolve(ctx);
if (Args[i] == nullptr) fail = true;
if (Args[i]->ValueType != ctx.ReturnProto->ReturnTypes[i])
{
Args[i] = new FxTypeCast(Args[i], ctx.ReturnProto->ReturnTypes[i], false, false);
Args[i] = Args[i]->Resolve(ctx);
if (Args[i] == nullptr) fail = true;
}
}
if (fail)
{
Expand Down Expand Up @@ -11065,6 +11153,7 @@ FxLocalVariableDeclaration::FxLocalVariableDeclaration(PType *type, FName name,
if (type == TypeFVector2) type = TypeVector2;
else if (type == TypeFVector3) type = TypeVector3;
else if (type == TypeFVector4) type = TypeVector4;
else if (type == TypeFQuaternion) type = TypeQuaternion;

ValueType = type;
VarFlags = varflags;
Expand Down
15 changes: 15 additions & 0 deletions src/common/scripting/backend/codegen.h
Expand Up @@ -343,6 +343,7 @@ class FxExpression
bool IsVector2() const { return ValueType == TypeVector2 || ValueType == TypeFVector2; };
bool IsVector3() const { return ValueType == TypeVector3 || ValueType == TypeFVector3; };
bool IsVector4() const { return ValueType == TypeVector4 || ValueType == TypeFVector4; };
bool IsQuaternion() const { return ValueType == TypeQuaternion || ValueType == TypeFQuaternion; };
bool IsBoolCompat() const { return ValueType->isScalar(); }
bool IsObject() const { return ValueType->isObjectPointer(); }
bool IsArray() const { return ValueType->isArray() || (ValueType->isPointer() && ValueType->toPointer()->PointedType->isArray()); }
Expand Down Expand Up @@ -577,6 +578,20 @@ class FxVectorValue : public FxExpression
};


//==========================================================================
//
//
//
//==========================================================================

class FxQuaternionValue : public FxVectorValue
{
public:
FxQuaternionValue(FxExpression* x, FxExpression* y, FxExpression* z, FxExpression* w, const FScriptPosition& sc);
FxExpression* Resolve(FCompileContext&);
};


//==========================================================================
//
//
Expand Down
38 changes: 38 additions & 0 deletions src/common/scripting/core/types.cpp
Expand Up @@ -62,9 +62,11 @@ PStateLabel *TypeStateLabel;
PStruct *TypeVector2;
PStruct *TypeVector3;
PStruct* TypeVector4;
PStruct* TypeQuaternion;
PStruct* TypeFVector2;
PStruct* TypeFVector3;
PStruct* TypeFVector4;
PStruct* TypeFQuaternion;
PStruct *TypeColorStruct;
PStruct *TypeStringStruct;
PPointer *TypeNullPtr;
Expand Down Expand Up @@ -410,6 +412,40 @@ void PType::StaticInit()
TypeFVector4->RegCount = 4;
TypeFVector4->isOrdered = true;


TypeQuaternion = new PStruct(NAME_Quat, nullptr);
TypeQuaternion->AddField(NAME_X, TypeFloat64);
TypeQuaternion->AddField(NAME_Y, TypeFloat64);
TypeQuaternion->AddField(NAME_Z, TypeFloat64);
TypeQuaternion->AddField(NAME_W, TypeFloat64);
// allow vector access.
TypeQuaternion->Symbols.AddSymbol(Create<PField>(NAME_XYZ, TypeVector3, VARF_Transient, 0));
TypeQuaternion->Symbols.AddSymbol(Create<PField>(NAME_XY, TypeVector2, VARF_Transient, 0));
TypeTable.AddType(TypeQuaternion, NAME_Struct);
TypeQuaternion->loadOp = OP_LV4;
TypeQuaternion->storeOp = OP_SV4;
TypeQuaternion->moveOp = OP_MOVEV4;
TypeQuaternion->RegType = REGT_FLOAT;
TypeQuaternion->RegCount = 4;
TypeQuaternion->isOrdered = true;

TypeFQuaternion = new PStruct(NAME_FQuat, nullptr);
TypeFQuaternion->AddField(NAME_X, TypeFloat32);
TypeFQuaternion->AddField(NAME_Y, TypeFloat32);
TypeFQuaternion->AddField(NAME_Z, TypeFloat32);
TypeFQuaternion->AddField(NAME_W, TypeFloat32);
// allow accessing xyz as a vector3
TypeFQuaternion->Symbols.AddSymbol(Create<PField>(NAME_XYZ, TypeFVector3, VARF_Transient, 0));
TypeFQuaternion->Symbols.AddSymbol(Create<PField>(NAME_XY, TypeFVector2, VARF_Transient, 0));
TypeTable.AddType(TypeFQuaternion, NAME_Struct);
TypeFQuaternion->loadOp = OP_LFV4;
TypeFQuaternion->storeOp = OP_SFV4;
TypeFQuaternion->moveOp = OP_MOVEV4;
TypeFQuaternion->RegType = REGT_FLOAT;
TypeFQuaternion->RegCount = 4;
TypeFQuaternion->isOrdered = true;


Namespaces.GlobalNamespace->Symbols.AddSymbol(Create<PSymbolType>(NAME_sByte, TypeSInt8));
Namespaces.GlobalNamespace->Symbols.AddSymbol(Create<PSymbolType>(NAME_Byte, TypeUInt8));
Namespaces.GlobalNamespace->Symbols.AddSymbol(Create<PSymbolType>(NAME_Short, TypeSInt16));
Expand All @@ -429,9 +465,11 @@ void PType::StaticInit()
Namespaces.GlobalNamespace->Symbols.AddSymbol(Create<PSymbolType>(NAME_Vector2, TypeVector2));
Namespaces.GlobalNamespace->Symbols.AddSymbol(Create<PSymbolType>(NAME_Vector3, TypeVector3));
Namespaces.GlobalNamespace->Symbols.AddSymbol(Create<PSymbolType>(NAME_Vector4, TypeVector4));
Namespaces.GlobalNamespace->Symbols.AddSymbol(Create<PSymbolType>(NAME_Quat, TypeQuaternion));
Namespaces.GlobalNamespace->Symbols.AddSymbol(Create<PSymbolType>(NAME_FVector2, TypeFVector2));
Namespaces.GlobalNamespace->Symbols.AddSymbol(Create<PSymbolType>(NAME_FVector3, TypeFVector3));
Namespaces.GlobalNamespace->Symbols.AddSymbol(Create<PSymbolType>(NAME_FVector4, TypeFVector4));
Namespaces.GlobalNamespace->Symbols.AddSymbol(Create<PSymbolType>(NAME_FQuat, TypeFQuaternion));
}


Expand Down
2 changes: 2 additions & 0 deletions src/common/scripting/core/types.h
Expand Up @@ -619,6 +619,8 @@ extern PStruct* TypeVector4;
extern PStruct* TypeFVector2;
extern PStruct* TypeFVector3;
extern PStruct* TypeFVector4;
extern PStruct* TypeQuaternion;
extern PStruct* TypeFQuaternion;
extern PStruct *TypeColorStruct;
extern PStruct *TypeStringStruct;
extern PStatePointer *TypeState;
Expand Down

0 comments on commit 31ac1bd

Please sign in to comment.