- added LengthSquared and Angle intrinsics for all vector types, also allow calling VectorAngle with a full vector as a single parameter.

This commit is contained in:
Christoph Oelckers 2022-11-13 07:47:42 +01:00
parent 54f1cabed9
commit f3b33f7cf8
4 changed files with 126 additions and 24 deletions

View file

@ -151,7 +151,9 @@ xx(stateinfo)
xx(DamageFunction) xx(DamageFunction)
xx(Length) xx(Length)
xx(LengthSquared)
xx(Unit) xx(Unit)
xx(Angle)
xx(Size) xx(Size)
xx(Push) xx(Push)
xx(Insert) xx(Insert)

View file

@ -5127,6 +5127,23 @@ FxExpression *FxATan2::Resolve(FCompileContext &ctx)
return this; 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<FxConstant*>(val)->GetValue().GetFloat()));
return reg;
}
return val->Emit(build);
}
//========================================================================== //==========================================================================
// //
// //
@ -5143,6 +5160,61 @@ ExpEmit FxATan2::Emit(VMFunctionBuilder *build)
return out; 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); 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<FxConstant*>(val)->GetValue().GetFloat()));
return reg;
}
return val->Emit(build);
}
//========================================================================== //==========================================================================
// //
// //
@ -7967,10 +8022,18 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
case NAME_ATan2: case NAME_ATan2:
case NAME_VectorAngle: 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); if (ArgList.Size() == 2)
ArgList[0] = ArgList[1] = nullptr; {
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; break;
@ -8201,7 +8264,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
else if (Self->IsVector()) else if (Self->IsVector())
{ {
// handle builtins: Vectors got 2: Length and Unit. // 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) if (ArgList.Size() > 0)
{ {
@ -9190,7 +9253,23 @@ FxExpression *FxVectorBuiltin::Resolve(FCompileContext &ctx)
{ {
SAFE_RESOLVE(Self, ctx); SAFE_RESOLVE(Self, ctx);
assert(Self->IsVector()); // should never be created for anything else. 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; 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); 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); 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_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); build->Emit(vecSize == 2 ? OP_DIVVF2_RR : vecSize == 3 ? OP_DIVVF3_RR : OP_DIVVF4_RR, to.RegNum, op.RegNum, len.RegNum);
len.Free(build); len.Free(build);
} }
else if (Function == NAME_Angle)
{
build->Emit(OP_ATAN2, to.RegNum, op.RegNum + 1, op.RegNum);
}
op.Free(build); op.Free(build);
return to; return to;
} }

View file

@ -248,6 +248,7 @@ enum EFxType
EFX_Conditional, EFX_Conditional,
EFX_Abs, EFX_Abs,
EFX_ATan2, EFX_ATan2,
EFX_ATan2Vec,
EFX_New, EFX_New,
EFX_MinMax, EFX_MinMax,
EFX_Random, EFX_Random,
@ -1201,6 +1202,18 @@ private:
ExpEmit ToReg(VMFunctionBuilder *build, FxExpression *val); 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);
};
//========================================================================== //==========================================================================
// //
// //

View file

@ -481,7 +481,7 @@ xx(ResolveState)
// UDMF keywords (todo: take these out of the global name table // UDMF keywords (todo: take these out of the global name table
xx(Alpha) xx(Alpha)
xx(Angle) //xx(Angle)
xx(Args) xx(Args)
xx(CeilingZ) xx(CeilingZ)
xx(FloorZ) xx(FloorZ)