mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-13 07:57:51 +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(CosH)
|
||||||
xx(SinH)
|
xx(SinH)
|
||||||
xx(TanH)
|
xx(TanH)
|
||||||
|
xx(ATan2)
|
||||||
|
xx(VectorAngle)
|
||||||
xx(Alpha)
|
xx(Alpha)
|
||||||
xx(Angle)
|
xx(Angle)
|
||||||
xx(Args)
|
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 *ParseRandomPick(FScanner &sc, FName identifier, PClassActor *cls);
|
||||||
static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls);
|
static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls);
|
||||||
static FxExpression *ParseAbs(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 *ParseMinMax(FScanner &sc, FName identifier, PClassActor *cls);
|
||||||
static FxExpression *ParseClamp(FScanner &sc, PClassActor *cls);
|
static FxExpression *ParseClamp(FScanner &sc, PClassActor *cls);
|
||||||
|
|
||||||
|
@ -386,6 +387,9 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
|
||||||
return ParseClamp(sc, cls);
|
return ParseClamp(sc, cls);
|
||||||
case NAME_Abs:
|
case NAME_Abs:
|
||||||
return ParseAbs(sc, cls);
|
return ParseAbs(sc, cls);
|
||||||
|
case NAME_ATan2:
|
||||||
|
case NAME_VectorAngle:
|
||||||
|
return ParseAtan2(sc, identifier, cls);
|
||||||
default:
|
default:
|
||||||
args = new FArgumentList;
|
args = new FArgumentList;
|
||||||
func = dyn_cast<PFunction>(cls->Symbols.FindSymbol(identifier, true));
|
func = dyn_cast<PFunction>(cls->Symbols.FindSymbol(identifier, true));
|
||||||
|
@ -511,6 +515,15 @@ static FxExpression *ParseAbs(FScanner &sc, PClassActor *cls)
|
||||||
return new FxAbs(x);
|
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)
|
static FxExpression *ParseMinMax(FScanner &sc, FName identifier, PClassActor *cls)
|
||||||
{
|
{
|
||||||
TArray<FxExpression*> list;
|
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
|
class FxMinMax : public FxExpression
|
||||||
{
|
{
|
||||||
TDeletingArray<FxExpression *> choices;
|
TDeletingArray<FxExpression *> choices;
|
||||||
|
|
|
@ -1991,6 +1991,99 @@ ExpEmit FxAbs::Emit(VMFunctionBuilder *build)
|
||||||
return out;
|
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];
|
reg.f[a] = reg.f[B] > konstf[C] ? reg.f[B] : konstf[C];
|
||||||
NEXTOP;
|
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):
|
OP(FLOP):
|
||||||
ASSERTF(a); ASSERTF(B);
|
ASSERTF(a); ASSERTF(B);
|
||||||
fb = reg.f[B];
|
fb = reg.f[B];
|
||||||
|
|
|
@ -174,6 +174,7 @@ xx(MINF_RR, min, RFRFRF), // fA = min(fB),fkC)
|
||||||
xx(MINF_RK, min, RFRFKF),
|
xx(MINF_RK, min, RFRFKF),
|
||||||
xx(MAXF_RR, max, RFRFRF), // fA = max(fB),fkC)
|
xx(MAXF_RR, max, RFRFRF), // fA = max(fB),fkC)
|
||||||
xx(MAXF_RK, max, RFRFKF),
|
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(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_R, beq, CFRR), // if ((fB == fkC) != (A & 1)) then pc++
|
||||||
xx(EQF_K, beq, CFRK),
|
xx(EQF_K, beq, CFRK),
|
||||||
|
|
Loading…
Reference in a new issue