diff --git a/src/common/engine/namedef.h b/src/common/engine/namedef.h index 5e30591acb..a67676c7a2 100644 --- a/src/common/engine/namedef.h +++ b/src/common/engine/namedef.h @@ -151,7 +151,9 @@ xx(stateinfo) xx(DamageFunction) xx(Length) +xx(LengthSquared) xx(Unit) +xx(Angle) xx(Size) xx(Push) xx(Insert) diff --git a/src/common/scripting/backend/codegen.cpp b/src/common/scripting/backend/codegen.cpp index 7aedc48aed..bd597388de 100644 --- a/src/common/scripting/backend/codegen.cpp +++ b/src/common/scripting/backend/codegen.cpp @@ -5127,6 +5127,23 @@ FxExpression *FxATan2::Resolve(FCompileContext &ctx) return this; } +//========================================================================== +// +// The atan2 opcode only takes registers as parameters, so any constants +// must be loaded into registers first. +// +//========================================================================== +ExpEmit FxATan2::ToReg(VMFunctionBuilder* build, FxExpression* val) +{ + if (val->isConstant()) + { + ExpEmit reg(build, REGT_FLOAT); + build->Emit(OP_LKF, reg.RegNum, build->GetConstantFloat(static_cast(val)->GetValue().GetFloat())); + return reg; + } + return val->Emit(build); +} + //========================================================================== // // @@ -5143,6 +5160,61 @@ ExpEmit FxATan2::Emit(VMFunctionBuilder *build) return out; } +//========================================================================== +// +// +// +//========================================================================== +FxATan2Vec::FxATan2Vec(FxExpression* v, const FScriptPosition& pos) + : FxExpression(EFX_ATan2Vec, pos) +{ + vval = v; +} + +//========================================================================== +// +// +// +//========================================================================== +FxATan2Vec::~FxATan2Vec() +{ + SAFE_DELETE(vval); +} + +//========================================================================== +// +// +// +//========================================================================== +FxExpression* FxATan2Vec::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(vval, ctx); + + if (!vval->IsVector()) + { + ScriptPosition.Message(MSG_ERROR, "vector value expected for parameter"); + delete this; + return nullptr; + } + ValueType = TypeFloat64; + return this; +} + +//========================================================================== +// +// +// +//========================================================================== +ExpEmit FxATan2Vec::Emit(VMFunctionBuilder* build) +{ + ExpEmit vreg = vval->Emit(build); + vreg.Free(build); + ExpEmit out(build, REGT_FLOAT); + build->Emit(OP_ATAN2, out.RegNum, vreg.RegNum + 1, vreg.RegNum); + return out; +} + //========================================================================== // // @@ -5278,23 +5350,6 @@ ExpEmit FxNew::Emit(VMFunctionBuilder *build) return emitters.EmitCall(build); } -//========================================================================== -// -// The atan2 opcode only takes registers as parameters, so any constants -// must be loaded into registers first. -// -//========================================================================== -ExpEmit FxATan2::ToReg(VMFunctionBuilder *build, FxExpression *val) -{ - if (val->isConstant()) - { - ExpEmit reg(build, REGT_FLOAT); - build->Emit(OP_LKF, reg.RegNum, build->GetConstantFloat(static_cast(val)->GetValue().GetFloat())); - return reg; - } - return val->Emit(build); -} - //========================================================================== // // @@ -7967,10 +8022,18 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) case NAME_ATan2: case NAME_VectorAngle: - if (CheckArgSize(MethodName, ArgList, 2, 2, ScriptPosition)) + if (CheckArgSize(MethodName, ArgList, 1, 2, ScriptPosition)) { - func = MethodName == NAME_ATan2 ? new FxATan2(ArgList[0], ArgList[1], ScriptPosition) : new FxATan2(ArgList[1], ArgList[0], ScriptPosition); - ArgList[0] = ArgList[1] = nullptr; + if (ArgList.Size() == 2) + { + func = MethodName == NAME_ATan2 ? new FxATan2(ArgList[0], ArgList[1], ScriptPosition) : new FxATan2(ArgList[1], ArgList[0], ScriptPosition); + ArgList[0] = ArgList[1] = nullptr; + } + else + { + func = new FxATan2Vec(ArgList[0], ScriptPosition); + ArgList[0] = nullptr; + } } break; @@ -8201,7 +8264,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) else if (Self->IsVector()) { // handle builtins: Vectors got 2: Length and Unit. - if (MethodName == NAME_Length || MethodName == NAME_Unit) + if (MethodName == NAME_Length || MethodName == NAME_LengthSquared || MethodName == NAME_Unit || MethodName == NAME_Angle) { if (ArgList.Size() > 0) { @@ -9190,7 +9253,23 @@ FxExpression *FxVectorBuiltin::Resolve(FCompileContext &ctx) { SAFE_RESOLVE(Self, ctx); assert(Self->IsVector()); // should never be created for anything else. - ValueType = Function == NAME_Length ? TypeFloat64 : Self->ValueType; + switch (Function.GetIndex()) + { + case NAME_Length: + case NAME_LengthSquared: + case NAME_Angle: + ValueType = TypeFloat64; + break; + + case NAME_Unit: + ValueType = Self->ValueType; + break; + + default: + ValueType = TypeError; + assert(false); + break; + } return this; } @@ -9206,13 +9285,21 @@ ExpEmit FxVectorBuiltin::Emit(VMFunctionBuilder *build) { build->Emit(vecSize == 2 ? OP_LENV2 : vecSize == 3 ? OP_LENV3 : OP_LENV4, to.RegNum, op.RegNum); } - else + else if (Function == NAME_LengthSquared) + { + build->Emit(vecSize == 2 ? OP_DOTV2_RR : vecSize == 3 ? OP_DOTV3_RR : OP_DOTV4_RR, to.RegNum, op.RegNum, op.RegNum); + } + else if (Function == NAME_Unit) { ExpEmit len(build, REGT_FLOAT); build->Emit(vecSize == 2 ? OP_LENV2 : vecSize == 3 ? OP_LENV3 : OP_LENV4, len.RegNum, op.RegNum); build->Emit(vecSize == 2 ? OP_DIVVF2_RR : vecSize == 3 ? OP_DIVVF3_RR : OP_DIVVF4_RR, to.RegNum, op.RegNum, len.RegNum); len.Free(build); } + else if (Function == NAME_Angle) + { + build->Emit(OP_ATAN2, to.RegNum, op.RegNum + 1, op.RegNum); + } op.Free(build); return to; } diff --git a/src/common/scripting/backend/codegen.h b/src/common/scripting/backend/codegen.h index aa1b9ee2db..ca8f0ce45d 100644 --- a/src/common/scripting/backend/codegen.h +++ b/src/common/scripting/backend/codegen.h @@ -248,6 +248,7 @@ enum EFxType EFX_Conditional, EFX_Abs, EFX_ATan2, + EFX_ATan2Vec, EFX_New, EFX_MinMax, EFX_Random, @@ -1201,6 +1202,18 @@ private: ExpEmit ToReg(VMFunctionBuilder *build, FxExpression *val); }; +class FxATan2Vec : public FxExpression +{ + FxExpression* vval; + +public: + + FxATan2Vec(FxExpression* y, const FScriptPosition& pos); + ~FxATan2Vec(); + FxExpression* Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder* build); +}; + //========================================================================== // // diff --git a/src/namedef_custom.h b/src/namedef_custom.h index 15a9a29107..e55d5cb079 100644 --- a/src/namedef_custom.h +++ b/src/namedef_custom.h @@ -481,7 +481,7 @@ xx(ResolveState) // UDMF keywords (todo: take these out of the global name table xx(Alpha) -xx(Angle) +//xx(Angle) xx(Args) xx(CeilingZ) xx(FloorZ)