Add atan2, which was conspicuously absent, to the VM

- DECORATE now has atan2(y,x) and VectorAngle(x,y) functions. They are
  identical except for the order of their parameters. The returned angle
  is in degrees (not radians).
This commit is contained in:
Randy Heit 2016-04-18 23:06:17 -05:00
commit e83bc53678
6 changed files with 135 additions and 0 deletions

View file

@ -1991,6 +1991,99 @@ ExpEmit FxAbs::Emit(VMFunctionBuilder *build)
return out;
}
//==========================================================================
//
//
//
//==========================================================================
FxATan2::FxATan2(FxExpression *y, FxExpression *x, const FScriptPosition &pos)
: FxExpression(pos)
{
yval = y;
xval = x;
}
//==========================================================================
//
//
//
//==========================================================================
FxATan2::~FxATan2()
{
SAFE_DELETE(yval);
SAFE_DELETE(xval);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxATan2::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(yval, ctx);
SAFE_RESOLVE(xval, ctx);
if (!yval->IsNumeric() || !xval->IsNumeric())
{
ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter");
delete this;
return NULL;
}
if (yval->isConstant() && xval->isConstant())
{
double y = static_cast<FxConstant *>(yval)->GetValue().GetFloat();
double x = static_cast<FxConstant *>(xval)->GetValue().GetFloat();
FxExpression *z = new FxConstant(g_atan2(y, x) * (180 / M_PI), ScriptPosition);
delete this;
return z;
}
if (yval->ValueType->GetRegType() != REGT_FLOAT && !yval->isConstant())
{
yval = new FxFloatCast(yval);
}
if (xval->ValueType->GetRegType() != REGT_FLOAT && !xval->isConstant())
{
xval = new FxFloatCast(xval);
}
ValueType = TypeFloat64;
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpEmit FxATan2::Emit(VMFunctionBuilder *build)
{
ExpEmit yreg = ToReg(build, yval);
ExpEmit xreg = ToReg(build, xval);
yreg.Free(build);
xreg.Free(build);
ExpEmit out(build, REGT_FLOAT);
build->Emit(OP_ATAN2, out.RegNum, yreg.RegNum, xreg.RegNum);
return out;
}
//==========================================================================
//
// 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);
}
//==========================================================================
//
//