Skip to content
This repository has been archived by the owner on Jan 5, 2024. It is now read-only.

Commit

Permalink
Avoid costly dynamic casts, using virtual function call instead
Browse files Browse the repository at this point in the history
  • Loading branch information
Causeless committed Nov 27, 2023
1 parent d393e1f commit 267a44a
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 41 deletions.
6 changes: 6 additions & 0 deletions Entities/AtomGroup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include "LimbPath.h"
#include "ConsoleMan.h"

#include "tracy/Tracy.hpp"

namespace RTE {

ConcreteClassInfo(AtomGroup, Entity, 500);
Expand Down Expand Up @@ -333,6 +335,8 @@ namespace RTE {

// TODO: Break down and rework this trainwreck.
float AtomGroup::Travel(Vector &position, Vector &velocity, Matrix &rotation, float &angularVel, bool &didWrap, Vector &totalImpulse, float mass, float travelTime, bool callOnBounce, bool callOnSink, bool scenePreLocked) {
ZoneScoped;

RTEAssert(m_OwnerMOSR, "Tried to travel an AtomGroup that has no parent!");

m_MomentOfInertia = GetMomentOfInertia();
Expand Down Expand Up @@ -769,6 +773,8 @@ namespace RTE {

// TODO: Break down and rework this dumpsterfire.
Vector AtomGroup::PushTravel(Vector &position, const Vector &velocity, float pushForce, bool &didWrap, float travelTime, bool callOnBounce, bool callOnSink, bool scenePreLocked) {
ZoneScoped;

RTEAssert(m_OwnerMOSR, "Tried to push-travel an AtomGroup that has no parent!");

didWrap = false;
Expand Down
10 changes: 10 additions & 0 deletions Entities/MOPixel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,16 @@ namespace RTE {
m_Atom->SetTrailLength(trailLength);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool MOPixel::HitTestAtPixel(int pixelX, int pixelY) const {
if (!GetsHitByMOs() || GetRootParent()->GetTraveling()) {
return false;
}

return m_Pos.GetFloorIntX() == pixelX && m_Pos.GetFloorIntY() == pixelY;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void MOPixel::Travel() {
Expand Down
8 changes: 8 additions & 0 deletions Entities/MOPixel.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,14 @@ namespace RTE {
/// </summary>
/// <param name="staininess">The new staininess value.</param>
void SetStaininess(float staininess) { m_Staininess = staininess; }

/// <summary>
/// Whether a set of X, Y coordinates overlap us (in world space).
/// </summary>
/// <param name="pixelX">The given X coordinate, in world space.</param>
/// <param name="pixelY">The given Y coordinate, in world space.</param>
/// <returns>Whether the given coordinate overlap us.</returns>
bool HitTestAtPixel(int pixelX, int pixelY) const override;
#pragma endregion

#pragma region Virtual Override Methods
Expand Down
20 changes: 20 additions & 0 deletions Entities/MOSprite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,26 @@ void MOSprite::Destroy(bool notInherited)
Clear();
}

bool MOSprite::HitTestAtPixel(int pixelX, int pixelY) const {
if (!GetsHitByMOs() || GetRootParent()->GetTraveling()) {
return false;
}

Vector distanceBetweenTestPositionAndMO = g_SceneMan.ShortestDistance(m_Pos, Vector(static_cast<float>(pixelX), static_cast<float>(pixelY)));
if (distanceBetweenTestPositionAndMO.MagnitudeIsGreaterThan(m_SpriteRadius)) {
return false;
}

// Check the scene position in the current local space of the MO, accounting for Position, Sprite Offset, Angle and HFlipped.
//TODO Account for Scale as well someday, maybe.
Matrix rotation = m_Rotation; // <- Copy to non-const variable so / operator overload works.
Vector entryPos = (distanceBetweenTestPositionAndMO / rotation).GetXFlipped(m_HFlipped) - m_SpriteOffset;
int localX = entryPos.GetFloorIntX();
int localY = entryPos.GetFloorIntY();

BITMAP* sprite = m_aSprite[m_Frame];
return is_inside_bitmap(sprite, localX, localY, 0) && _getpixel(sprite, localX, localY) != ColorKeys::g_MaskColor;
}

//////////////////////////////////////////////////////////////////////////////////////////
// Method: SetFrame
Expand Down
8 changes: 8 additions & 0 deletions Entities/MOSprite.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,14 @@ class MOSprite : public MovableObject {
/// <returns>The previous rotational angle in radians.</returns>
float GetPrevRotAngle() const { return m_PrevRotation.GetRadAngle(); }

/// <summary>
/// Whether a set of X, Y coordinates overlap us (in world space).
/// </summary>
/// <param name="pixelX">The given X coordinate, in world space.</param>
/// <param name="pixelY">The given Y coordinate, in world space.</param>
/// <returns>Whether the given coordinate overlap us.</returns>
bool HitTestAtPixel(int pixelX, int pixelY) const override;

//////////////////////////////////////////////////////////////////////////////////////////
// Method: GetAngularVel
//////////////////////////////////////////////////////////////////////////////////////////
Expand Down
7 changes: 7 additions & 0 deletions Entities/MovableObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,13 @@ enum MOType

virtual bool IsDrawnAfterParent() const { return true; }

/// <summary>
/// Whether a set of X, Y coordinates overlap us (in world space).
/// </summary>
/// <param name="pixelX">The given X coordinate, in world space.</param>
/// <param name="pixelY">The given Y coordinate, in world space.</param>
/// <returns>Whether the given coordinate overlap us.</returns>
virtual bool HitTestAtPixel(int pixelX, int pixelY) const { return false; }

//////////////////////////////////////////////////////////////////////////////////////////
// Method: HasObject
Expand Down
39 changes: 7 additions & 32 deletions Managers/MovableMan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,45 +183,20 @@ MovableObject * MovableMan::GetMOFromID(MOID whichID) {

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool MovableMan::HitTestMOAtPixel(const MovableObject &mo, int pixelX, int pixelY) const {
if (!mo.GetsHitByMOs() || mo.GetRootParent()->GetTraveling()) {
return false;
}

if (const MOSprite *moSprite = dynamic_cast<const MOSprite *>(&mo); moSprite) {
Vector distanceBetweenTestPositionAndMO = g_SceneMan.ShortestDistance(moSprite->GetPos(), Vector(static_cast<float>(pixelX), static_cast<float>(pixelY)));
if (distanceBetweenTestPositionAndMO.MagnitudeIsLessThan(moSprite->GetRadius())) {
// Check the scene position in the current local space of the MO, accounting for Position, Sprite Offset, Angle and HFlipped.
//TODO Account for Scale as well someday, maybe.
Matrix rotation = moSprite->GetRotMatrix(); // <- Copy to non-const variable so / operator overload works.
Vector entryPos = (distanceBetweenTestPositionAndMO / rotation).GetXFlipped(moSprite->IsHFlipped()) - moSprite->GetSpriteOffset();
int localX = entryPos.GetFloorIntX();
int localY = entryPos.GetFloorIntY();

BITMAP *sprite = moSprite->GetSpriteFrame(moSprite->GetFrame());
return is_inside_bitmap(sprite, localX, localY, 0) && _getpixel(sprite, localX, localY) != ColorKeys::g_MaskColor;
}
} else if (const MOPixel *moPixel = dynamic_cast<const MOPixel *>(&mo); moPixel) {
const Vector &pos = moPixel->GetPos();
return pos.GetFloorIntX() == pixelX && pos.GetFloorIntY() == pixelY;
}

return false;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

MOID MovableMan::GetMOIDPixel(int pixelX, int pixelY, const std::vector<int> &moidList) {
// Note - We loop through the MOs in reverse to make sure that the topmost (last drawn) MO that overlaps the specified coordinates is the one returned.
for (auto itr = moidList.rbegin(), itrEnd = moidList.rend(); itr < itrEnd; ++itr) {
MOID moid = *itr;

const MovableObject *mo = GetMOFromID(moid);

RTEAssert(mo, "Null MO found in MOID list!");
if (mo && mo->GetScale() == 0) {
if (mo == nullptr) {
continue;
}

if (mo->GetScale() == 0.0f) {
return g_NoMOID;
}
if (mo && HitTestMOAtPixel(*mo, pixelX, pixelY)) {
} else if (mo->HitTestAtPixel(pixelX, pixelY)) {
return moid;
}
}
Expand Down
9 changes: 0 additions & 9 deletions Managers/MovableMan.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,15 +151,6 @@ class MovableMan : public Singleton<MovableMan>, public Serializable {

int GetMOIDCount() { return m_MOIDIndex.size(); }

/// <summary>
/// Tests whether the given MovableObject is currently at the specified pixel coordinates.
/// </summary>
/// <param name="mo">The MovableObject to test.</param>
/// <param name="pixelX">The X coordinate of the Scene pixel to test.</param>
/// <param name="pixelY">The Y coordinate of the Scene pixel to test.</param>
/// <returns>Whether the given MovableObject is currently at the specified pixel coordinates.</returns>
bool HitTestMOAtPixel(const MovableObject &mo, int pixelX, int pixelY) const;

/// <summary>
/// Gets a MOID from pixel coordinates in the Scene.
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions System/Atom.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "Atom.h"

#include "SLTerrain.h"
#include "MovableMan.h"
#include "MovableObject.h"
Expand All @@ -7,6 +8,8 @@
#include "PresetMan.h"
#include "Actor.h"

#include "tracy/Tracy.hpp"

namespace RTE {

const std::string Atom::c_ClassName = "Atom";
Expand Down Expand Up @@ -601,6 +604,8 @@ namespace RTE {
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int Atom::Travel(float travelTime, bool autoTravel, bool scenePreLocked) {
ZoneScoped;

if (!m_OwnerMO) {
RTEAbort("Traveling an Atom without a parent MO!");
return travelTime;
Expand Down

0 comments on commit 267a44a

Please sign in to comment.