Merge branch 'zmaster'

This commit is contained in:
Christoph Oelckers 2016-02-26 11:54:08 +01:00
commit bb4bd76257
15 changed files with 261 additions and 118 deletions

View file

@ -818,22 +818,28 @@ public:
return ( abs(X() - other->X()) < blockdist && abs(Y() - other->Y()) < blockdist);
}
// 'absolute' is reserved for a linked portal implementation which needs
// to distinguish between portal-aware and portal-unaware distance calculation.
fixed_t AproxDistance(AActor *other, bool absolute = false)
{
return P_AproxDistance(X() - other->X(), Y() - other->Y());
}
// same with 'ref' here.
fixed_t AproxDistance(fixed_t otherx, fixed_t othery, AActor *ref = NULL)
fixed_t AproxDistance(fixed_t otherx, fixed_t othery)
{
return P_AproxDistance(X() - otherx, Y() - othery);
}
fixed_t AngleTo(fixed_t otherx, fixed_t othery)
{
return R_PointToAngle2(X(), Y(), otherx, othery);
}
// 'absolute' is reserved for a linked portal implementation which needs
// to distinguish between portal-aware and portal-unaware distance calculation.
fixed_t AproxDistance(AActor *other, bool absolute = false)
{
fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this);
return P_AproxDistance(X() - otherpos.x, Y() - otherpos.y);
}
fixed_t AproxDistance(AActor *other, fixed_t xadd, fixed_t yadd, bool absolute = false)
{
return P_AproxDistance(X() - other->X() + xadd, Y() - other->Y() + yadd);
fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this);
return P_AproxDistance(X() - otherpos.x + xadd, Y() - otherpos.y + yadd);
}
fixed_t AproxDistance3D(AActor *other, bool absolute = false)
@ -844,18 +850,21 @@ public:
// more precise, but slower version, being used in a few places
fixed_t Distance2D(AActor *other, bool absolute = false)
{
return xs_RoundToInt(TVector2<double>(X() - other->X(), Y() - other->Y()).Length());
fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this);
return xs_RoundToInt(TVector2<double>(X() - otherpos.x, Y() - otherpos.y).Length());
}
// a full 3D version of the above
fixed_t Distance3D(AActor *other, bool absolute = false)
{
return xs_RoundToInt(TVector3<double>(X() - other->X(), Y() - other->Y(), Z() - other->Z()).Length());
fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this);
return xs_RoundToInt(TVector3<double>(X() - otherpos.x, Y() - otherpos.y, Z() - otherpos.z).Length());
}
angle_t AngleTo(AActor *other, bool absolute = false) const
angle_t AngleTo(AActor *other, bool absolute = false)
{
return R_PointToAngle2(X(), Y(), other->X(), other->Y());
fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this);
return R_PointToAngle2(X(), Y(), otherpos.x, otherpos.y);
}
angle_t AngleTo(AActor *other, fixed_t oxofs, fixed_t oyofs, bool absolute = false) const
@ -863,53 +872,71 @@ public:
return R_PointToAngle2(X(), Y(), other->X() + oxofs, other->Y() + oyofs);
}
fixed_t AngleTo(fixed_t otherx, fixed_t othery, AActor *ref = NULL)
{
return R_PointToAngle2(X(), Y(), otherx, othery);
}
fixed_t AngleXYTo(fixed_t myx, fixed_t myy, AActor *other, bool absolute = false)
{
return R_PointToAngle2(myx, myy, other->X(), other->Y());
}
fixedvec2 Vec2To(AActor *other) const
{
fixedvec2 ret = { other->X() - X(), other->Y() - Y() };
fixedvec3 otherpos = other->PosRelative(this);
fixedvec2 ret = { otherpos.x - X(), otherpos.y - Y() };
return ret;
}
fixedvec3 Vec3To(AActor *other) const
{
fixedvec3 ret = { other->X() - X(), other->Y() - Y(), other->Z() - Z() };
fixedvec3 otherpos = other->PosRelative(this);
fixedvec3 ret = { otherpos.x - X(), otherpos.y - Y(), otherpos.z - Z() };
return ret;
}
fixedvec2 Vec2Offset(fixed_t dx, fixed_t dy, bool absolute = false) const
fixedvec2 Vec2Offset(fixed_t dx, fixed_t dy, bool absolute = false)
{
fixedvec2 ret = { X() + dx, Y() + dy };
return ret;
if (absolute)
{
fixedvec2 ret = { X() + dx, Y() + dy };
return ret;
}
else return P_GetOffsetPosition(this, dx, dy);
}
fixedvec2 Vec2Angle(fixed_t length, angle_t angle, bool absolute = false) const
fixedvec2 Vec2Angle(fixed_t length, angle_t angle, bool absolute = false)
{
fixedvec2 ret = { X() + FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]),
Y() + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]) };
return ret;
if (absolute)
{
fixedvec2 ret = { X() + FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]),
Y() + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]) };
return ret;
}
else return P_GetOffsetPosition(this, FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]));
}
fixedvec3 Vec3Offset(fixed_t dx, fixed_t dy, fixed_t dz, bool absolute = false) const
fixedvec3 Vec3Offset(fixed_t dx, fixed_t dy, fixed_t dz, bool absolute = false)
{
fixedvec3 ret = { X() + dx, Y() + dy, Z() + dz };
return ret;
if (absolute)
{
fixedvec3 ret = { X() + dx, Y() + dy, Z() + dz };
return ret;
}
else
{
fixedvec2 op = P_GetOffsetPosition(this, dx, dy);
fixedvec3 pos = { op.x, op.y, Z() + dz };
return pos;
}
}
fixedvec3 Vec3Angle(fixed_t length, angle_t angle, fixed_t dz, bool absolute = false) const
fixedvec3 Vec3Angle(fixed_t length, angle_t angle, fixed_t dz, bool absolute = false)
{
fixedvec3 ret = { X() + FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]),
if (absolute)
{
fixedvec3 ret = { X() + FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]),
Y() + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]), Z() + dz };
return ret;
return ret;
}
else
{
fixedvec2 op = P_GetOffsetPosition(this, FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]));
fixedvec3 pos = { op.x, op.y, Z() + dz };
return pos;
}
}
void ClearInterpolation();
@ -1190,7 +1217,7 @@ public:
return __pos;
}
fixedvec3 PosRelative(AActor *other) const;
fixedvec3 PosRelative(const AActor *other) const;
fixedvec3 PosRelative(sector_t *sec) const;
fixedvec3 PosRelative(line_t *line) const;

View file

@ -513,7 +513,7 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z,
z -= source->floorclip;
th = Spawn (type, x, y, z, ALLOW_REPLACE);
th->target = source; // Originator
an = source->AngleXYTo(x, y, dest);
an = th->AngleTo(dest);
if (dest->flags & MF_SHADOW)
{ // Invisible target
an += pr_kmissile.Random2()<<21;
@ -522,7 +522,7 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z,
an >>= ANGLETOFINESHIFT;
th->velx = FixedMul (th->Speed, finecosine[an]);
th->vely = FixedMul (th->Speed, finesine[an]);
dist = dest->AproxDistance (x, y, source) / th->Speed;
dist = dest->AproxDistance (th) / th->Speed;
if (dist < 1)
{
dist = 1;

View file

@ -284,8 +284,18 @@ xx(FRandom)
xx(Random2)
xx(RandomPick)
xx(FRandomPick)
xx(Exp)
xx(Log10)
xx(Ceil)
xx(ACos)
xx(ASin)
xx(ATan)
xx(Cos)
xx(Sin)
xx(Tan)
xx(CosH)
xx(SinH)
xx(TanH)
xx(Alpha)
xx(Angle)
xx(Args)
@ -322,6 +332,7 @@ xx(Radius)
xx(ReactionTime)
xx(MeleeRange)
xx(Speed)
xx(Clamp)
// Various actor names which are used internally
xx(MapSpot)

View file

@ -856,7 +856,7 @@ bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item)
void FMultiBlockLinesIterator::startIteratorForGroup(int group)
{
offset = Displacements(basegroup, group);
offset = Displacements.getOffset(basegroup, group);
offset.x += checkpoint.x;
offset.y += checkpoint.y;
bbox.setBox(offset.x, offset.y, checkpoint.z);
@ -1088,7 +1088,7 @@ bool FMultiBlockThingsIterator::Next(FMultiBlockThingsIterator::CheckResult *ite
if (thing != NULL)
{
item->thing = thing;
item->position = checkpoint + Displacements(basegroup, thing->Sector->PortalGroup);
item->position = checkpoint + Displacements.getOffset(basegroup, thing->Sector->PortalGroup);
item->portalflags = portalflags;
return true;
}
@ -1127,7 +1127,7 @@ bool FMultiBlockThingsIterator::Next(FMultiBlockThingsIterator::CheckResult *ite
void FMultiBlockThingsIterator::startIteratorForGroup(int group)
{
fixedvec2 offset = Displacements(basegroup, group);
fixedvec2 offset = Displacements.getOffset(basegroup, group);
offset.x += checkpoint.x;
offset.y += checkpoint.y;
bbox.setBox(offset.x, offset.y, checkpoint.z);

View file

@ -897,9 +897,9 @@ fixed_t sector_t::HighestCeilingAt(fixed_t x, fixed_t y, sector_t **resultsec)
// Continue until we find a blocking portal or a portal below where we actually are.
while (!check->PortalBlocksMovement(ceiling) && planeheight < check->SkyBoxes[ceiling]->threshold)
{
FDisplacement &disp = check->CeilingDisplacement();
x += disp.pos.x;
y += disp.pos.y;
fixedvec2 pos = check->CeilingDisplacement();
x += pos.x;
y += pos.y;
planeheight = check->SkyBoxes[ceiling]->threshold;
check = P_PointInSector(x, y);
}
@ -921,9 +921,9 @@ fixed_t sector_t::LowestFloorAt(fixed_t x, fixed_t y, sector_t **resultsec)
// Continue until we find a blocking portal or a portal above where we actually are.
while (!check->PortalBlocksMovement(floor) && planeheight > check->SkyBoxes[floor]->threshold)
{
FDisplacement &disp = check->FloorDisplacement();
x += disp.pos.x;
y += disp.pos.y;
fixedvec2 pos = check->FloorDisplacement();
x += pos.x;
y += pos.y;
planeheight = check->SkyBoxes[floor]->threshold;
check = P_PointInSector(x, y);
}
@ -960,9 +960,9 @@ fixed_t sector_t::NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, int flag
}
else
{
FDisplacement &disp = sec->CeilingDisplacement();
x += disp.pos.x;
y += disp.pos.y;
fixedvec2 pos = sec->CeilingDisplacement();
x += pos.x;
y += pos.y;
planeheight = sec->SkyBoxes[ceiling]->threshold;
sec = P_PointInSector(x, y);
}
@ -1003,9 +1003,9 @@ fixed_t sector_t::NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, int flags,
}
else
{
FDisplacement &disp = sec->FloorDisplacement();
x += disp.pos.x;
y += disp.pos.y;
fixedvec2 pos = sec->FloorDisplacement();
x += pos.x;
y += pos.y;
planeheight = sec->SkyBoxes[floor]->threshold;
sec = P_PointInSector(x, y);
}

View file

@ -786,7 +786,7 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs,
if (flags & WARPF_WARPINTERPOLATION)
{
// This just translates the movement but doesn't change the vector
fixedvec3 displacedold = old + Displacements(oldpgroup, caller->Sector->PortalGroup);
fixedvec3 displacedold = old + Displacements.getOffset(oldpgroup, caller->Sector->PortalGroup);
caller->PrevX += caller->X() - displacedold.x;
caller->PrevY += caller->Y() - displacedold.y;
caller->PrevZ += caller->Z() - displacedold.z;
@ -795,8 +795,8 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs,
else if (flags & WARPF_COPYINTERPOLATION)
{
// Map both positions of the reference actor to the current portal group
fixedvec3 displacedold = old + Displacements(reference->PrevPortalGroup, caller->Sector->PortalGroup);
fixedvec3 displacedref = old + Displacements(reference->Sector->PortalGroup, caller->Sector->PortalGroup);
fixedvec3 displacedold = old + Displacements.getOffset(reference->PrevPortalGroup, caller->Sector->PortalGroup);
fixedvec3 displacedref = old + Displacements.getOffset(reference->Sector->PortalGroup, caller->Sector->PortalGroup);
caller->PrevX = caller->X() + displacedold.x - displacedref.x;
caller->PrevY = caller->Y() + displacedold.y - displacedref.y;
caller->PrevZ = caller->Z() + displacedold.z - displacedref.z;

View file

@ -121,6 +121,11 @@ static void BuildBlockmap()
{
PortalBlockmap.containsLines = true;
block.portallines.Push(ld);
block.neighborContainsLines = true;
if (x > 0) PortalBlockmap(x - 1, y).neighborContainsLines = true;
if (y > 0) PortalBlockmap(x, y - 1).neighborContainsLines = true;
if (x < PortalBlockmap.dx - 1) PortalBlockmap(x + 1, y).neighborContainsLines = true;
if (y < PortalBlockmap.dy - 1) PortalBlockmap(x, y + 1).neighborContainsLines = true;
}
}
}
@ -691,15 +696,23 @@ void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy)
fixedvec2 P_GetOffsetPosition(AActor *actor, fixed_t dx, fixed_t dy)
{
fixedvec3 dest = { actor->X() + dx, actor->Y() + dy };
fixedvec2 dest = { actor->X() + dx, actor->Y() + dy };
if (PortalBlockmap.containsLines)
{
fixed_t actx = actor->X(), acty = actor->Y();
// Try some easily discoverable early-out first. If we know that the trace cannot possibly find a portal, this saves us from calling the traverser completely for vast parts of the map.
if (dx < 128 * FRACUNIT && dy < 128 * FRACUNIT)
{
fixed_t blockx = GetSafeBlockX(actx - bmaporgx);
fixed_t blocky = GetSafeBlockX(acty - bmaporgy);
if (blockx < 0 || blocky < 0 || blockx >= bmapwidth || blocky >= bmapheight || !PortalBlockmap(blockx, blocky).neighborContainsLines) return dest;
}
FLinePortalTraverse it;
bool repeat;
do
{
it.init(actx, acty, dx, dy, PT_ADDLINES);
it.init(actx, acty, dx, dy, PT_ADDLINES|PT_DELTA);
intercept_t *in;
repeat = false;
@ -1159,9 +1172,9 @@ bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t
while (!wsec->PortalBlocksMovement(sector_t::ceiling) && upperz > wsec->SkyBoxes[sector_t::ceiling]->threshold)
{
sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector;
FDisplacement &disp = Displacements(startgroup, othersec->PortalGroup);
fixed_t dx = position.x + disp.pos.x;
fixed_t dy = position.y + disp.pos.y;
fixedvec2 pos = Displacements.getOffset(startgroup, othersec->PortalGroup);
fixed_t dx = position.x + pos.x;
fixed_t dy = position.y + pos.y;
processMask.setBit(othersec->PortalGroup);
out.Add(othersec->PortalGroup|FPortalGroupArray::UPPER);
wsec = P_PointInSector(dx, dy); // get upper sector at the exact spot we want to check and repeat
@ -1171,9 +1184,9 @@ bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t
while (!wsec->PortalBlocksMovement(sector_t::floor) && position.z < wsec->SkyBoxes[sector_t::floor]->threshold)
{
sector_t *othersec = wsec->SkyBoxes[sector_t::floor]->Sector;
FDisplacement &disp = Displacements(startgroup, othersec->PortalGroup);
fixed_t dx = position.x + disp.pos.x;
fixed_t dy = position.y + disp.pos.y;
fixedvec2 pos = Displacements.getOffset(startgroup, othersec->PortalGroup);
fixed_t dx = position.x + pos.x;
fixed_t dy = position.y + pos.y;
processMask.setBit(othersec->PortalGroup|FPortalGroupArray::LOWER);
out.Add(othersec->PortalGroup);
wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat

View file

@ -30,10 +30,6 @@ struct FDisplacement
bool isSet;
BYTE indirect; // just for illustration.
operator fixedvec2()
{
return pos;
}
};
struct FDisplacementTable
@ -55,9 +51,18 @@ struct FDisplacementTable
FDisplacement &operator()(int x, int y)
{
if (x == y) return data[0]; // shortcut for the most common case
return data[x + size*y];
}
fixedvec2 getOffset(int x, int y) const
{
if (x == y)
{
fixedvec2 nulvec = { 0,0 };
return nulvec; // shortcut for the most common case
}
return data[x + size*y].pos;
}
};
extern FDisplacementTable Displacements;
@ -72,7 +77,13 @@ extern FDisplacementTable Displacements;
struct FPortalBlock
{
bool neighborContainsLines; // this is for skipping the traverser and exiting early if we can quickly decide that there's no portals nearby.
TArray<line_t*> portallines;
FPortalBlock()
{
neighborContainsLines = false;
}
};
struct FPortalBlockmap
@ -187,5 +198,6 @@ void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle);
void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z);
void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy);
fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y);
fixedvec2 P_GetOffsetPosition(AActor *actor, fixed_t dx, fixed_t dy);
#endif

View file

@ -838,14 +838,14 @@ struct sector_t
}
// These may only be called if the portal has been validated
FDisplacement &FloorDisplacement()
fixedvec2 FloorDisplacement()
{
return Displacements(PortalGroup, SkyBoxes[sector_t::floor]->Sector->PortalGroup);
return Displacements.getOffset(PortalGroup, SkyBoxes[sector_t::floor]->Sector->PortalGroup);
}
FDisplacement &CeilingDisplacement()
fixedvec2 CeilingDisplacement()
{
return Displacements(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup);
return Displacements.getOffset(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup);
}
int GetTerrain(int pos) const;
@ -1375,24 +1375,24 @@ inline sector_t *P_PointInSector(fixed_t x, fixed_t y)
return P_PointInSubsector(x, y)->sector;
}
inline fixedvec3 AActor::PosRelative(AActor *other) const
inline fixedvec3 AActor::PosRelative(const AActor *other) const
{
return __pos + Displacements(Sector->PortalGroup, other->Sector->PortalGroup);
return __pos + Displacements.getOffset(Sector->PortalGroup, other->Sector->PortalGroup);
}
inline fixedvec3 AActor::PosRelative(sector_t *sec) const
{
return __pos + Displacements(Sector->PortalGroup, sec->PortalGroup);
return __pos + Displacements.getOffset(Sector->PortalGroup, sec->PortalGroup);
}
inline fixedvec3 AActor::PosRelative(line_t *line) const
{
return __pos + Displacements(Sector->PortalGroup, line->frontsector->PortalGroup);
return __pos + Displacements.getOffset(Sector->PortalGroup, line->frontsector->PortalGroup);
}
inline fixedvec3 PosRelative(const fixedvec3 &pos, line_t *line, sector_t *refsec = NULL)
{
return pos + Displacements(refsec->PortalGroup, line->frontsector->PortalGroup);
return pos + Displacements.getOffset(refsec->PortalGroup, line->frontsector->PortalGroup);
}
inline void AActor::ClearInterpolation()

View file

@ -583,7 +583,7 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi
}
int oldgroup = R_PointInSubsector(iview->oviewx, iview->oviewy)->sector->PortalGroup;
int newgroup = R_PointInSubsector(iview->nviewx, iview->nviewy)->sector->PortalGroup;
fixedvec2 disp = Displacements(oldgroup, newgroup);
fixedvec2 disp = Displacements.getOffset(oldgroup, newgroup);
viewx = iview->oviewx + FixedMul (frac, iview->nviewx - iview->oviewx - disp.x);
viewy = iview->oviewy + FixedMul (frac, iview->nviewy - iview->oviewy - disp.y);
viewz = iview->oviewz + FixedMul (frac, iview->nviewz - iview->oviewz);

View file

@ -323,6 +323,40 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetDistance)
return 0;
}
//==========================================================================
//
// GetSpawnHealth
//
//==========================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpawnHealth)
{
if (numret > 0)
{
PARAM_PROLOGUE;
PARAM_OBJECT(self, AActor);
ret->SetInt(self->SpawnHealth());
return 1;
}
return 0;
}
//==========================================================================
//
// GetGibHealth
//
//==========================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetGibHealth)
{
if (numret > 0)
{
PARAM_PROLOGUE;
PARAM_OBJECT(self, AActor);
ret->SetInt(self->GetGibHealth());
return 1;
}
return 0;
}
//===========================================================================
//
// __decorate_internal_state__
@ -5147,7 +5181,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack)
if (spawnblood)
{
P_SpawnBlood(bloodpos, angle, newdam > 0 ? newdam : damage, self->target);
P_TraceBleed(newdam > 0 ? newdam : damage, self->target, self->AngleTo(dx, dy, self->target), 0);
P_TraceBleed(newdam > 0 ? newdam : damage, self->target, self);
}
}
}

View file

@ -57,6 +57,7 @@ static FxExpression *ParseRandomPick(FScanner &sc, FName identifier, PClassActor
static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls);
static FxExpression *ParseAbs(FScanner &sc, PClassActor *cls);
static FxExpression *ParseMinMax(FScanner &sc, FName identifier, PClassActor *cls);
static FxExpression *ParseClamp(FScanner &sc, PClassActor *cls);
//
// ParseExpression
@ -381,6 +382,8 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
case NAME_Min:
case NAME_Max:
return ParseMinMax(sc, identifier, cls);
case NAME_Clamp:
return ParseClamp(sc, cls);
case NAME_Abs:
return ParseAbs(sc, cls);
default:
@ -521,3 +524,23 @@ static FxExpression *ParseMinMax(FScanner &sc, FName identifier, PClassActor *cl
}
return new FxMinMax(list, identifier, sc);
}
static FxExpression *ParseClamp(FScanner &sc, PClassActor *cls)
{
FxExpression *src = ParseExpressionM(sc, cls);
sc.MustGetToken(',');
FxExpression *min = ParseExpressionM(sc, cls);
sc.MustGetToken(',');
FxExpression *max = ParseExpressionM(sc, cls);
sc.MustGetToken(')');
// Build clamp(a,x,y) as min(max(a,x),y)
TArray<FxExpression *> list(2);
list.Reserve(2);
list[0] = src;
list[1] = min;
FxExpression *maxexpr = new FxMinMax(list, NAME_Max, sc);
list[0] = maxexpr;
list[1] = max;
return new FxMinMax(list, NAME_Min, sc);
}

View file

@ -830,19 +830,19 @@ public:
//==========================================================================
//
// FxGlobalFunctionCall
// FxFlopFunctionCall
//
//==========================================================================
class FxGlobalFunctionCall : public FxExpression
class FxFlopFunctionCall : public FxExpression
{
FName Name;
int Index;
FArgumentList *ArgList;
public:
FxGlobalFunctionCall(FName fname, FArgumentList *args, const FScriptPosition &pos);
~FxGlobalFunctionCall();
FxFlopFunctionCall(int index, FArgumentList *args, const FScriptPosition &pos);
~FxFlopFunctionCall();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};

View file

@ -54,6 +54,36 @@
#include "vmbuilder.h"
#include "v_text.h"
struct FLOP
{
ENamedName Name;
int Flop;
double (*Evaluate)(double);
};
// Decorate operates on degrees, so the evaluate functions need to convert
// degrees to radians for those that work with angles.
static const FLOP FxFlops[] =
{
{ NAME_Exp, FLOP_EXP, [](double v) { return exp(v); } },
{ NAME_Log, FLOP_LOG, [](double v) { return log(v); } },
{ NAME_Log10, FLOP_LOG10, [](double v) { return log10(v); } },
{ NAME_Sqrt, FLOP_SQRT, [](double v) { return sqrt(v); } },
{ NAME_Ceil, FLOP_CEIL, [](double v) { return ceil(v); } },
{ NAME_Floor, FLOP_FLOOR, [](double v) { return floor(v); } },
{ NAME_ACos, FLOP_ACOS_DEG, [](double v) { return acos(v) * (180.0 / M_PI); } },
{ NAME_ASin, FLOP_ASIN_DEG, [](double v) { return asin(v) * (180.0 / M_PI); } },
{ NAME_ATan, FLOP_ATAN_DEG, [](double v) { return atan(v) * (180.0 / M_PI); } },
{ NAME_Cos, FLOP_COS_DEG, [](double v) { return cos(v * (M_PI / 180.0)); } },
{ NAME_Sin, FLOP_SIN_DEG, [](double v) { return sin(v * (M_PI / 180.0)); } },
{ NAME_Tan, FLOP_TAN_DEG, [](double v) { return tan(v * (M_PI / 180.0)); } },
{ NAME_CosH, FLOP_COSH, [](double v) { return cosh(v); } },
{ NAME_SinH, FLOP_SINH, [](double v) { return sinh(v); } },
{ NAME_TanH, FLOP_TANH, [](double v) { return tanh(v); } },
};
ExpEmit::ExpEmit(VMFunctionBuilder *build, int type)
: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false)
{
@ -3146,20 +3176,21 @@ FxFunctionCall::~FxFunctionCall()
FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
{
// There's currently only 3 global functions.
// If this changes later, it won't be here!
if (MethodName == NAME_Sin || MethodName == NAME_Cos || MethodName == NAME_Sqrt)
for (int i = 0; i < countof(FxFlops); ++i)
{
if (Self != NULL)
if (MethodName == FxFlops[i].Name)
{
ScriptPosition.Message(MSG_ERROR, "Global functions cannot have a self pointer");
if (Self != NULL)
{
ScriptPosition.Message(MSG_ERROR, "Global functions cannot have a self pointer");
delete this;
return NULL;
}
FxExpression *x = new FxFlopFunctionCall(i, ArgList, ScriptPosition);
ArgList = NULL;
delete this;
return NULL;
return x->Resolve(ctx);
}
FxExpression *x = new FxGlobalFunctionCall(MethodName, ArgList, ScriptPosition);
ArgList = NULL;
delete this;
return x->Resolve(ctx);
}
int min, max, special;
@ -3483,10 +3514,11 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall)
//
//==========================================================================
FxGlobalFunctionCall::FxGlobalFunctionCall(FName fname, FArgumentList *args, const FScriptPosition &pos)
FxFlopFunctionCall::FxFlopFunctionCall(int index, FArgumentList *args, const FScriptPosition &pos)
: FxExpression(pos)
{
Name = fname;
assert(index >= 0 && index < countof(FxFlops) && "FLOP index out of range");
Index = index;
ArgList = args;
}
@ -3496,18 +3528,18 @@ FxGlobalFunctionCall::FxGlobalFunctionCall(FName fname, FArgumentList *args, con
//
//==========================================================================
FxGlobalFunctionCall::~FxGlobalFunctionCall()
FxFlopFunctionCall::~FxFlopFunctionCall()
{
SAFE_DELETE(ArgList);
}
FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx)
FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
if (ArgList == NULL || ArgList->Size() != 1)
{
ScriptPosition.Message(MSG_ERROR, "%s only has one parameter", Name.GetChars());
ScriptPosition.Message(MSG_ERROR, "%s only has one parameter", FName(FxFlops[Index].Name).GetChars());
delete this;
return NULL;
}
@ -3528,15 +3560,7 @@ FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx)
if ((*ArgList)[0]->isConstant())
{
double v = static_cast<FxConstant *>((*ArgList)[0])->GetValue().GetFloat();
if (Name == NAME_Sqrt)
{
v = sqrt(v);
}
else
{
v *= M_PI / 180.0; // convert from degrees to radians
v = (Name == NAME_Sin) ? sin(v) : cos(v);
}
v = FxFlops[Index].Evaluate(v);
FxExpression *x = new FxConstant(v, ScriptPosition);
delete this;
return x;
@ -3554,15 +3578,12 @@ FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx)
//
//==========================================================================
ExpEmit FxGlobalFunctionCall::Emit(VMFunctionBuilder *build)
ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build)
{
ExpEmit v = (*ArgList)[0]->Emit(build);
assert(!v.Konst && v.RegType == REGT_FLOAT);
build->Emit(OP_FLOP, v.RegNum, v.RegNum,
(Name == NAME_Sqrt) ? FLOP_SQRT :
(Name == NAME_Sin) ? FLOP_SIN_DEG :
FLOP_COS_DEG);
build->Emit(OP_FLOP, v.RegNum, v.RegNum, FxFlops[Index].Flop);
return v;
}

View file

@ -42,6 +42,8 @@ ACTOR Actor native //: Thinker
native bool IsPointerEqual(int ptr_select1, int ptr_select2);
native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT);
native float GetDistance(bool checkz, int ptr = AAPTR_DEFAULT);
native int GetSpawnHealth();
native int GetGibHealth();
// Action functions
// Meh, MBF redundant functions. Only for DeHackEd support.