mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-11 07:11:54 +00:00
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:
parent
30a530b178
commit
e83bc53678
6 changed files with 135 additions and 0 deletions
|
@ -296,6 +296,8 @@ xx(Tan)
|
|||
xx(CosH)
|
||||
xx(SinH)
|
||||
xx(TanH)
|
||||
xx(ATan2)
|
||||
xx(VectorAngle)
|
||||
xx(Alpha)
|
||||
xx(Angle)
|
||||
xx(Args)
|
||||
|
|
|
@ -56,6 +56,7 @@ static FxExpression *ParseRandom(FScanner &sc, FName identifier, PClassActor *cl
|
|||
static FxExpression *ParseRandomPick(FScanner &sc, FName identifier, PClassActor *cls);
|
||||
static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls);
|
||||
static FxExpression *ParseAbs(FScanner &sc, PClassActor *cls);
|
||||
static FxExpression *ParseAtan2(FScanner &sc, FName identifier, PClassActor *cls);
|
||||
static FxExpression *ParseMinMax(FScanner &sc, FName identifier, PClassActor *cls);
|
||||
static FxExpression *ParseClamp(FScanner &sc, PClassActor *cls);
|
||||
|
||||
|
@ -386,6 +387,9 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
|
|||
return ParseClamp(sc, cls);
|
||||
case NAME_Abs:
|
||||
return ParseAbs(sc, cls);
|
||||
case NAME_ATan2:
|
||||
case NAME_VectorAngle:
|
||||
return ParseAtan2(sc, identifier, cls);
|
||||
default:
|
||||
args = new FArgumentList;
|
||||
func = dyn_cast<PFunction>(cls->Symbols.FindSymbol(identifier, true));
|
||||
|
@ -511,6 +515,15 @@ static FxExpression *ParseAbs(FScanner &sc, PClassActor *cls)
|
|||
return new FxAbs(x);
|
||||
}
|
||||
|
||||
static FxExpression *ParseAtan2(FScanner &sc, FName identifier, PClassActor *cls)
|
||||
{
|
||||
FxExpression *a = ParseExpressionM(sc, cls);
|
||||
sc.MustGetToken(',');
|
||||
FxExpression *b = ParseExpressionM(sc, cls);
|
||||
sc.MustGetToken(')');
|
||||
return identifier == NAME_ATan2 ? new FxATan2(a, b, sc) : new FxATan2(b, a, sc);
|
||||
}
|
||||
|
||||
static FxExpression *ParseMinMax(FScanner &sc, FName identifier, PClassActor *cls)
|
||||
{
|
||||
TArray<FxExpression*> list;
|
||||
|
|
|
@ -623,6 +623,27 @@ public:
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxATan2 : public FxExpression
|
||||
{
|
||||
FxExpression *yval, *xval;
|
||||
|
||||
public:
|
||||
|
||||
FxATan2(FxExpression *y, FxExpression *x, const FScriptPosition &pos);
|
||||
~FxATan2();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
|
||||
private:
|
||||
ExpEmit ToReg(VMFunctionBuilder *build, FxExpression *val);
|
||||
};
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxMinMax : public FxExpression
|
||||
{
|
||||
TDeletingArray<FxExpression *> choices;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
|
|
@ -1039,6 +1039,11 @@ begin:
|
|||
reg.f[a] = reg.f[B] > konstf[C] ? reg.f[B] : konstf[C];
|
||||
NEXTOP;
|
||||
|
||||
OP(ATAN2):
|
||||
ASSERTF(a); ASSERTF(B); ASSERTF(C);
|
||||
reg.f[a] = g_atan2(reg.f[B], reg.f[C]) * (180 / M_PI);
|
||||
NEXTOP;
|
||||
|
||||
OP(FLOP):
|
||||
ASSERTF(a); ASSERTF(B);
|
||||
fb = reg.f[B];
|
||||
|
|
|
@ -174,6 +174,7 @@ xx(MINF_RR, min, RFRFRF), // fA = min(fB),fkC)
|
|||
xx(MINF_RK, min, RFRFKF),
|
||||
xx(MAXF_RR, max, RFRFRF), // fA = max(fB),fkC)
|
||||
xx(MAXF_RK, max, RFRFKF),
|
||||
xx(ATAN2, atan2, RFRFRF), // fA = atan2(fB,fC), result is in degrees
|
||||
xx(FLOP, flop, RFRFI8), // fA = f(fB), where function is selected by C
|
||||
xx(EQF_R, beq, CFRR), // if ((fB == fkC) != (A & 1)) then pc++
|
||||
xx(EQF_K, beq, CFRK),
|
||||
|
|
Loading…
Reference in a new issue