Skip to content

Commit

Permalink
Fixed CollisionsDebugUI showing removed collision elements.
Browse files Browse the repository at this point in the history
The problem was removing collision boxes+tris from collision system was never implemented - the elements were only disabled and hiden, not removed.

Changes:
* New scripting API: `game.pruneCollisionElements()` - deletes boxes+tris marked for deletion.
* missions.as: invoke `game.pruneCollisionElements()` after unloading mission.
* CollisionsDebugUI: added button "prune collision elements" which forces the pruning.
* ProceduralRoad: fixed missing cleanup of collision mesh.
* Utils.h: `std::erase_if()` hack for Microsoft Visual Studio.
FIXUP: Collisions Debug UI: fixed typo in "Num collision meshes"
FIXUP: Portable `erase_if<>()`
  • Loading branch information
ohlidalp committed Oct 15, 2023
1 parent a5cdbb5 commit ac50e52
Show file tree
Hide file tree
Showing 12 changed files with 131 additions and 43 deletions.
16 changes: 11 additions & 5 deletions doc/angelscript/Script2Game/GameScriptClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,11 +338,6 @@ class GameScriptClass
*/
int getLoadedTerrain(string result);

/**
* Gets the currently loaded terrain instance
*/
TerrainClass@ getTerrain();

/**
* Checks if Caleum is enabled.
* @return true if Caleum is available
Expand Down Expand Up @@ -424,6 +419,17 @@ class GameScriptClass
* @return true if mouse points to the terrain and output coordinates are valid.
*/
bool getMousePositionOnTerrain(vector3 &out);

/**
* Gets the currently loaded terrain instance
*/
TerrainClass@ getTerrain();

/**
* Erases collision elements marked `pending_delete` and rebuilds lookup grid.
* Call this once after you've unloaded a mission or moved/removed things using editor.
*/
void pruneCollisionElements();

/// @}

Expand Down
1 change: 1 addition & 0 deletions resources/scripts/missions.as
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ class MissionManager
if (@loadedMission != null)
{
loadedMission.destroy();
game.pruneCollisionElements();
}
else
{
Expand Down
13 changes: 13 additions & 0 deletions source/main/gui/panels/GUI_CollisionsDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,19 @@ void CollisionsDebug::Draw()
ImGui::Checkbox("Draw labels", &m_draw_labels);
ImGui::Checkbox("Draw label types", &m_labels_draw_types);
ImGui::Checkbox("Sources on labels", &m_labels_draw_sources);
if (ImGui::Button("Prune collision elements"))
{
App::GetGameContext()->GetTerrain()->GetCollisions()->pruneCollisionElements();
}
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Collision elements are not removed immediatelly but marked as `pending_delete`.");
ImGui::Text("This button forces immediate deletion of those pending elements.");
ImGui::EndTooltip();
}
ImGui::Separator();

// EVENTBOX
Expand Down
1 change: 1 addition & 0 deletions source/main/physics/SimData.h
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,7 @@ struct collision_box_t
bool selfrotated;
bool camforced;
bool enabled;
bool pending_delete;
CollisionEventFilter event_filter;
short eventsourcenum;
Ogre::Vector3 lo; //!< absolute collision box
Expand Down
104 changes: 72 additions & 32 deletions source/main/physics/collision/Collisions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,17 @@
#include "ErrorUtils.h"
#include "GameContext.h"
#include "GfxScene.h"
#include "GUIManager.h"
#include "Landusemap.h"
#include "Language.h"
#include "MovableText.h"
#include "PlatformUtils.h"
#include "ScriptEngine.h"
#include "Terrain.h"
#include "Utils.h"

#include <algorithm>
#include <vector>

using namespace RoR;

Expand Down Expand Up @@ -350,6 +355,8 @@ void Collisions::removeCollisionBox(int number)
eventsources[m_collision_boxes[number].eventsourcenum].es_enabled = false;
}
// Is it worth to update the hashmap? ~ ulteq 01/19
// Eventually yes to tidy up debug views ~ only_a_ptr, 02/23
m_collision_boxes[number].pending_delete = true;
}
}

Expand All @@ -359,6 +366,32 @@ void Collisions::removeCollisionTri(int number)
{
m_collision_tris[number].enabled = false;
// Is it worth to update the hashmap? ~ ulteq 01/19
// Eventually yes to tidy up debug views ~ only_a_ptr, 02/23
m_collision_tris[number].pending_delete = true;
}
}

void Collisions::pruneCollisionElements()
{
// Clear the lookup grid
this->hash_purge();

// Dump outdated debug meshes
App::GetGuiManager()->CollisionsDebug.ClearEventBoxVisuals();
App::GetGuiManager()->CollisionsDebug.ClearCollisionMeshVisuals();

// Prune collision elements
EraseIf(m_collision_boxes, [](collision_box_t const& cbox) { return cbox.pending_delete; });
EraseIf(m_collision_tris, [](collision_tri_t const& ctri) {return ctri.pending_delete; });

// Rebuild hash map
for (size_t i = 0; i < m_collision_boxes.size(); i++)
{
hash_add_bounding_box(m_collision_boxes[i].lo, m_collision_boxes[i].hi, i);
}
for (size_t i = 0; i < m_collision_tris.size(); i++)
{
hash_add_bounding_box(m_collision_tris[i].aab.getMinimum(), m_collision_tris[i].aab.getMaximum(), i + hash_coll_element_t::ELEMENT_TRI_BASE_INDEX);
}
}

Expand All @@ -381,6 +414,34 @@ unsigned int Collisions::hashfunc(unsigned int cellid)
return hash&hashmask;
}

void Collisions::hash_purge()
{
for (size_t i = 0; i < HASH_SIZE; i++)
{
hashtable[i].clear();
}
}

void Collisions::hash_add_bounding_box(Ogre::Vector3 const& lo, Ogre::Vector3 const& hi, int value)
{
Vector3 ilo = Ogre::Vector3(lo / Ogre::Real(CELL_SIZE));
Vector3 ihi = Ogre::Vector3(hi / Ogre::Real(CELL_SIZE));

// clamp between 0 and MAXIMUM_CELL;
ilo.makeCeil(Ogre::Vector3(0.0f));
ilo.makeFloor(Ogre::Vector3(MAXIMUM_CELL));
ihi.makeCeil(Ogre::Vector3(0.0f));
ihi.makeFloor(Ogre::Vector3(MAXIMUM_CELL));

for (int i = ilo.x; i <= ihi.x; i++)
{
for (int j = ilo.z; j <= ihi.z; j++)
{
hash_add(i, j, value, hi.y);
}
}
}

void Collisions::hash_add(int cell_x, int cell_z, int value, float h)
{
unsigned int cell_id = (cell_x << 16) + cell_z;
Expand All @@ -406,6 +467,7 @@ int Collisions::addCollisionBox(bool rotating, bool virt, Vector3 pos, Ogre::Vec
collision_box_t coll_box;

coll_box.enabled = true;
coll_box.pending_delete = false;

// set refined box anyway
coll_box.relo = l*sc;
Expand Down Expand Up @@ -526,22 +588,7 @@ int Collisions::addCollisionBox(bool rotating, bool virt, Vector3 pos, Ogre::Vec
}

// register this collision box in the index
Vector3 ilo = Ogre::Vector3(coll_box.lo / Ogre::Real(CELL_SIZE));
Vector3 ihi = Ogre::Vector3(coll_box.hi / Ogre::Real(CELL_SIZE));

// clamp between 0 and MAXIMUM_CELL;
ilo.makeCeil(Ogre::Vector3(0.0f));
ilo.makeFloor(Ogre::Vector3(MAXIMUM_CELL));
ihi.makeCeil(Ogre::Vector3(0.0f));
ihi.makeFloor(Ogre::Vector3(MAXIMUM_CELL));

for (int i = ilo.x; i <= ihi.x; i++)
{
for (int j = ilo.z; j <= ihi.z; j++)
{
hash_add(i, j, coll_box_index,coll_box.hi.y);
}
}
this->hash_add_bounding_box(coll_box.lo, coll_box.hi, coll_box_index);

m_collision_aab.merge(AxisAlignedBox(coll_box.lo, coll_box.hi));
m_collision_boxes.push_back(coll_box);
Expand All @@ -557,6 +604,7 @@ int Collisions::addCollisionTri(Vector3 p1, Vector3 p2, Vector3 p3, ground_model
new_tri.c=p3;
new_tri.gm=gm;
new_tri.enabled=true;
new_tri.pending_delete = false;
// compute transformations
// base construction
Vector3 bx=p2-p1;
Expand All @@ -577,22 +625,8 @@ int Collisions::addCollisionTri(Vector3 p1, Vector3 p2, Vector3 p3, ground_model
new_tri.aab.setMaximum(new_tri.aab.getMaximum() + 0.1f);

// register this collision tri in the index
Ogre::Vector3 ilo(new_tri.aab.getMinimum() / Ogre::Real(CELL_SIZE));
Ogre::Vector3 ihi(new_tri.aab.getMaximum() / Ogre::Real(CELL_SIZE));

// clamp between 0 and MAXIMUM_CELL;
ilo.makeCeil(Ogre::Vector3(0.0f));
ilo.makeFloor(Ogre::Vector3(MAXIMUM_CELL));
ihi.makeCeil(Ogre::Vector3(0.0f));
ihi.makeFloor(Ogre::Vector3(MAXIMUM_CELL));

for (int i = ilo.x; i <= ihi.x; i++)
{
for (int j = ilo.z; j<=ihi.z; j++)
{
hash_add(i, j, new_tri_index + hash_coll_element_t::ELEMENT_TRI_BASE_INDEX, new_tri.aab.getMaximum().y);
}
}
this->hash_add_bounding_box(new_tri.aab.getMinimum(), new_tri.aab.getMaximum(),
new_tri_index + hash_coll_element_t::ELEMENT_TRI_BASE_INDEX);

m_collision_aab.merge(new_tri.aab);
m_collision_tris.push_back(new_tri);
Expand Down Expand Up @@ -1467,6 +1501,12 @@ void Collisions::registerCollisionMesh(Ogre::String const& srcname, Ogre::String
m_collision_meshes.push_back(rec);
}

void Collisions::unregisterCollisionMesh(Ogre::String const& meshname)
{
// This only erases the mesh record, but doesn't actually remove the collision triangles!
EraseIf(m_collision_meshes, [meshname](collision_mesh_t const& cmesh) { return cmesh.mesh_name == meshname; });
}

void Collisions::getMeshInformation(Mesh* mesh,size_t &vertex_count,Ogre::Vector3* &vertices,
size_t &index_count, unsigned* &indices, const Ogre::Vector3 &position,
const Ogre::Quaternion &orient, const Ogre::Vector3 &scale)
Expand Down
9 changes: 7 additions & 2 deletions source/main/physics/collision/Collisions.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct collision_tri_t
Ogre::Matrix3 reverse;
ground_model_t* gm;
bool enabled;
bool pending_delete;
};
typedef std::vector<collision_tri_t> CollisionTriVec;

Expand Down Expand Up @@ -157,6 +158,8 @@ class Collisions

const Ogre::Vector3 m_terrain_size;

void hash_purge(); //!< Remove everything from hashmap
void hash_add_bounding_box(Ogre::Vector3 const& lo, Ogre::Vector3 const& hi, int value);
void hash_add(int cell_x, int cell_z, int value, float h);
int hash_find(int cell_x, int cell_z); /// Returns index to 'hashtable'
unsigned int hashfunc(unsigned int cellid);
Expand Down Expand Up @@ -194,10 +197,12 @@ class Collisions
int addCollisionBox(bool rotating, bool virt, Ogre::Vector3 pos, Ogre::Vector3 rot, Ogre::Vector3 l, Ogre::Vector3 h, Ogre::Vector3 sr, const Ogre::String& eventname, const Ogre::String& instancename, bool forcecam, Ogre::Vector3 campos, Ogre::Vector3 sc = Ogre::Vector3::UNIT_SCALE, Ogre::Vector3 dr = Ogre::Vector3::ZERO, CollisionEventFilter event_filter = EVENT_ALL, int scripthandler = -1);
void addCollisionMesh(Ogre::String const& srcname, Ogre::String const& meshname, Ogre::Vector3 const& pos, Ogre::Quaternion const& q, Ogre::Vector3 const& scale, ground_model_t* gm = 0, std::vector<int>* collTris = 0); //!< generate collision tris from existing mesh resource
void registerCollisionMesh(Ogre::String const& srcname, Ogre::String const& meshname, Ogre::Vector3 const& pos, Ogre::AxisAlignedBox bounding_box, ground_model_t* gm, int ctri_start, int ctri_count); //!< Mark already generated collision tris as belonging to (virtual) mesh.
void unregisterCollisionMesh(Ogre::String const& meshname); //!< This only erases the mesh record, but doesn't actually remove the collision triangles!
int addCollisionTri(Ogre::Vector3 p1, Ogre::Vector3 p2, Ogre::Vector3 p3, ground_model_t* gm);
void createCollisionDebugVisualization(Ogre::SceneNode* root_node, Ogre::AxisAlignedBox const& area_limit, std::vector<Ogre::SceneNode*>& out_nodes);
void removeCollisionBox(int number);
void removeCollisionTri(int number);
void removeCollisionBox(int number); //!< Only marks it `pending_delete`, call `pruneCollisionElements()` afterwards!
void removeCollisionTri(int number); //!< Only marks it `pending_delete`, call `pruneCollisionElements()` afterwards!
void pruneCollisionElements(); //!< Deletes `pending_delete` elements and rebuilds the hashmap.
void clearEventCache() { m_last_called_cboxes.clear(); }

Ogre::AxisAlignedBox getCollisionAAB() { return m_collision_aab; };
Expand Down
10 changes: 9 additions & 1 deletion source/main/scripting/GameScript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -903,7 +903,7 @@ int GameScript::useOnlineAPI(const String& apiquery, const AngelScript::CScriptD
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.c_str());

CURLcode curl_result = curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);

Expand Down Expand Up @@ -1868,3 +1868,11 @@ std::string GameScript::CheckFileAccess(const char* func_name, const std::string
return basename + "." + extension;
}
}

void GameScript::pruneCollisionElements()
{
if (!HaveSimTerrain(__FUNCTION__))
return;

App::GetGameContext()->GetTerrain()->GetCollisions()->pruneCollisionElements();
}
6 changes: 6 additions & 0 deletions source/main/scripting/GameScript.h
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,12 @@ class GameScript

TerrainPtr getTerrain();

/**
* Erases collision elements marked `pending_delete` and rebuilds lookup grid.
* Call this once after you've unloaded a mission or moved/removed things using editor.
*/
void pruneCollisionElements();

/// @}

/// @name Character
Expand Down
1 change: 1 addition & 0 deletions source/main/scripting/bindings/GameScriptAngelscript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ void RoR::RegisterGameScript(asIScriptEngine *engine)
result = engine->RegisterObjectMethod("GameScriptClass", "void destroyObject(const string &in)", asMETHOD(GameScript, destroyObject), asCALL_THISCALL); ROR_ASSERT(result >= 0);
result = engine->RegisterObjectMethod("GameScriptClass", "bool getMousePositionOnTerrain(vector3 &out)", AngelScript::asMETHOD(GameScript, getMousePositionOnTerrain), AngelScript::asCALL_THISCALL); ROR_ASSERT(result >= 0);
result = engine->RegisterObjectMethod("GameScriptClass", "TerrainClassPtr@ getTerrain()", AngelScript::asMETHOD(GameScript,getTerrain), AngelScript::asCALL_THISCALL); ROR_ASSERT(result>=0);
result = engine->RegisterObjectMethod("GameScriptClass", "void pruneCollisionElements()", AngelScript::asMETHOD(GameScript, pruneCollisionElements), AngelScript::asCALL_THISCALL); ROR_ASSERT(result >= 0);

// > Character
result = engine->RegisterObjectMethod("GameScriptClass", "vector3 getPersonPosition()", asMETHOD(GameScript, getPersonPosition), asCALL_THISCALL); ROR_ASSERT(result >= 0);
Expand Down
7 changes: 4 additions & 3 deletions source/main/terrain/ProceduralRoad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ ProceduralRoad::~ProceduralRoad()
{
App::GetGameContext()->GetTerrain()->GetCollisions()->removeCollisionTri(number);
}
App::GetGameContext()->GetTerrain()->GetCollisions()->unregisterCollisionMesh(m_registered_coll_mesh_name);
}

void ProceduralRoad::finish()
Expand All @@ -68,13 +69,13 @@ void ProceduralRoad::finish()

createMesh();
String entity_name = String("RoadSystem_Instance-").append(StringConverter::toString(mid));
String mesh_name = String("RoadSystem-").append(StringConverter::toString(mid));
Entity* ec = App::GetGfxScene()->GetSceneManager()->createEntity(entity_name, mesh_name);
m_registered_coll_mesh_name = String("RoadSystem-").append(StringConverter::toString(mid));
Entity* ec = App::GetGfxScene()->GetSceneManager()->createEntity(entity_name, m_registered_coll_mesh_name);
snode = App::GetGfxScene()->GetSceneManager()->getRootSceneNode()->createChildSceneNode();
snode->attachObject(ec);

App::GetGameContext()->GetTerrain()->GetCollisions()->registerCollisionMesh(
"RoadSystem", mesh_name,
"RoadSystem", m_registered_coll_mesh_name,
ec->getBoundingBox().getCenter(), ec->getMesh()->getBounds(),
/*groundmodel:*/nullptr, registeredCollTris[0], (int)registeredCollTris.size());
}
Expand Down
1 change: 1 addition & 0 deletions source/main/terrain/ProceduralRoad.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class ProceduralRoad : public RefCountingObject<ProceduralRoad>
int mid = 0;
bool collision = true; //!< Register collision triangles?
std::vector<int> registeredCollTris;
std::string m_registered_coll_mesh_name;
};

/// @} // addtogroup Terrain
Expand Down
5 changes: 5 additions & 0 deletions source/main/utils/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

#include <MyGUI.h>
#include <OgreUTFString.h>
#include <vector>

namespace RoR {

Expand Down Expand Up @@ -109,3 +110,7 @@ void CvarAddFileToList(CVar* cvar, const std::string& filename);
void CvarRemoveFileFromList(CVar* cvar, const std::string& filename);

} // namespace RoR




0 comments on commit ac50e52

Please sign in to comment.