mirror of
https://github.com/Relintai/godot-lportal.git
synced 2024-11-11 10:52:09 +01:00
Optional convex hull bound for rooms
And also moved to a unity build.
This commit is contained in:
parent
ee06557f37
commit
7515bda46c
18
SCsub
18
SCsub
@ -2,14 +2,16 @@
|
|||||||
Import('env')
|
Import('env')
|
||||||
|
|
||||||
sources = [
|
sources = [
|
||||||
"register_types.cpp",
|
"lportal_all.cpp",
|
||||||
"lroom.cpp",
|
# "register_types.cpp",
|
||||||
"lroom_manager.cpp",
|
# "lroom.cpp",
|
||||||
"lroom_converter.cpp",
|
# "lroom_manager.cpp",
|
||||||
"lportal.cpp",
|
# "lroom_converter.cpp",
|
||||||
"lplanes_pool.cpp",
|
# "lportal.cpp",
|
||||||
"ldob.cpp",
|
# "lplanes_pool.cpp",
|
||||||
"lbitfield_dynamic.cpp",
|
# "ldob.cpp",
|
||||||
|
# "lbound.cpp",
|
||||||
|
# "lbitfield_dynamic.cpp",
|
||||||
]
|
]
|
||||||
|
|
||||||
module_env = env.Clone()
|
module_env = env.Clone()
|
||||||
|
38
lbound.cpp
Normal file
38
lbound.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include "lbound.h"
|
||||||
|
|
||||||
|
|
||||||
|
// get distance behind all planes and return the smallest..
|
||||||
|
// if inside this will be negative, if outside, positive
|
||||||
|
float LBound::GetClosestDistance(const Vector3 &pt) const
|
||||||
|
{
|
||||||
|
assert (m_Planes.size());
|
||||||
|
|
||||||
|
float closest = FLT_MAX;
|
||||||
|
|
||||||
|
for (int n=0; n<m_Planes.size(); n++)
|
||||||
|
{
|
||||||
|
float d = m_Planes[n].distance_to(pt);
|
||||||
|
|
||||||
|
// if in front of plane, outside the convex hull
|
||||||
|
if (d < closest)
|
||||||
|
closest = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LBound::IsPointWithin(const Vector3 &pt) const
|
||||||
|
{
|
||||||
|
for (int n=0; n<m_Planes.size(); n++)
|
||||||
|
{
|
||||||
|
float d = m_Planes[n].distance_to(pt);
|
||||||
|
|
||||||
|
// if in front of plane, outside the convex hull
|
||||||
|
if (d > 0.0f)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
19
lbound.h
Normal file
19
lbound.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "lvector.h"
|
||||||
|
|
||||||
|
// optional convex hull around rooms, to make it easier to determine which room a point is within
|
||||||
|
class LBound
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool IsPointWithin(const Vector3 &pt) const;
|
||||||
|
|
||||||
|
// get distance behind all planes and return the smallest..
|
||||||
|
// if inside this will be negative, if outside, positive
|
||||||
|
float GetClosestDistance(const Vector3 &pt) const;
|
||||||
|
|
||||||
|
// the bound is optional .. not all rooms have a bound
|
||||||
|
bool IsActive() const {return m_Planes.size() != 0;}
|
||||||
|
|
||||||
|
LVector<Plane> m_Planes;
|
||||||
|
};
|
10
lportal_all.cpp
Normal file
10
lportal_all.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// single compilation unit
|
||||||
|
#include "register_types.cpp"
|
||||||
|
#include "lroom.cpp"
|
||||||
|
#include "lroom_manager.cpp"
|
||||||
|
#include "lroom_converter.cpp"
|
||||||
|
#include "lportal.cpp"
|
||||||
|
#include "lplanes_pool.cpp"
|
||||||
|
#include "ldob.cpp"
|
||||||
|
#include "lbound.cpp"
|
||||||
|
#include "lbitfield_dynamic.cpp"
|
@ -418,6 +418,8 @@ void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, cons
|
|||||||
case LPortal::eClipResult::CLIP_PARTIAL:
|
case LPortal::eClipResult::CLIP_PARTIAL:
|
||||||
overall_res = res;
|
overall_res = res;
|
||||||
break;
|
break;
|
||||||
|
default: // suppress warning
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overall_res == LPortal::eClipResult::CLIP_OUTSIDE)
|
if (overall_res == LPortal::eClipResult::CLIP_OUTSIDE)
|
||||||
|
5
lroom.h
5
lroom.h
@ -30,6 +30,7 @@
|
|||||||
#include "scene/3d/spatial.h"
|
#include "scene/3d/spatial.h"
|
||||||
#include "lvector.h"
|
#include "lvector.h"
|
||||||
#include "ldob.h"
|
#include "ldob.h"
|
||||||
|
#include "lbound.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Lawn {class LBitField_Dynamic;}
|
namespace Lawn {class LBitField_Dynamic;}
|
||||||
@ -77,6 +78,10 @@ private:
|
|||||||
// frame counter when last touched .. prevents handling rooms multiple times
|
// frame counter when last touched .. prevents handling rooms multiple times
|
||||||
unsigned int m_uiFrameTouched;
|
unsigned int m_uiFrameTouched;
|
||||||
|
|
||||||
|
// optional bounding convex hull, for accurate detection of which room to start in
|
||||||
|
// when registering DOBs and teleporting them
|
||||||
|
LBound m_Bound;
|
||||||
|
|
||||||
String m_szName;
|
String m_szName;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "lroom_manager.h"
|
#include "lroom_manager.h"
|
||||||
#include "lportal.h"
|
#include "lportal.h"
|
||||||
#include "scene/3d/mesh_instance.h"
|
#include "scene/3d/mesh_instance.h"
|
||||||
|
#include "core/math/quick_hull.h"
|
||||||
|
|
||||||
// save typing, I am lazy
|
// save typing, I am lazy
|
||||||
#define LMAN m_pManager
|
#define LMAN m_pManager
|
||||||
@ -57,6 +58,7 @@ void LRoomConverter::Convert(LRoomManager &manager)
|
|||||||
|
|
||||||
Convert_Rooms();
|
Convert_Rooms();
|
||||||
Convert_Portals();
|
Convert_Portals();
|
||||||
|
Convert_Bounds();
|
||||||
LPortal::m_bRunning = true;
|
LPortal::m_bRunning = true;
|
||||||
|
|
||||||
// temp rooms no longer needed
|
// temp rooms no longer needed
|
||||||
@ -104,6 +106,17 @@ void LRoomConverter::Convert_Room_FindObjects_Recursive(Node * pParent, LRoom &l
|
|||||||
{
|
{
|
||||||
Node * pChild = pParent->get_child(n);
|
Node * pChild = pParent->get_child(n);
|
||||||
|
|
||||||
|
// we are not interested in portal meshes, as they will be deleted later in conversion
|
||||||
|
if (Node_IsPortal(pChild))
|
||||||
|
continue;
|
||||||
|
// we can optionally ignore nodes (they will still be shown / hidden with the room though)
|
||||||
|
if (Node_IsIgnore(pChild))
|
||||||
|
continue;
|
||||||
|
// not interested in bounds
|
||||||
|
if (Node_IsBound(pChild))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
|
||||||
VisualInstance * pVI = Object::cast_to<VisualInstance>(pChild);
|
VisualInstance * pVI = Object::cast_to<VisualInstance>(pChild);
|
||||||
if (pVI)
|
if (pVI)
|
||||||
{
|
{
|
||||||
@ -170,6 +183,113 @@ bool LRoomConverter::Convert_Room(Spatial * pNode, int lroomID)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LRoomConverter::Bound_AddPlaneIfUnique(LVector<Plane> &planes, const Plane &p)
|
||||||
|
{
|
||||||
|
for (int n=0; n<planes.size(); n++)
|
||||||
|
{
|
||||||
|
const Plane &o = planes[n];
|
||||||
|
|
||||||
|
// this is a fudge factor for how close planes can be to be considered the same ...
|
||||||
|
// to prevent ridiculous amounts of planes
|
||||||
|
const float d = 0.08f;
|
||||||
|
|
||||||
|
if (fabs(p.d - o.d) > d) continue;
|
||||||
|
|
||||||
|
float dot = p.normal.dot(o.normal);
|
||||||
|
if (dot < 0.98f) continue;
|
||||||
|
|
||||||
|
// match!
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// test
|
||||||
|
// Vector3 va(1, 0, 0);
|
||||||
|
// Vector3 vb(1, 0.2, 0);
|
||||||
|
// vb.normalize();
|
||||||
|
// float dot = va.dot(vb);
|
||||||
|
// print("va dot vb is " + String(Variant(dot)));
|
||||||
|
|
||||||
|
// is unique
|
||||||
|
// print("\t\t\t\tAdding bound plane : " + p);
|
||||||
|
|
||||||
|
planes.push_back(p);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LRoomConverter::Convert_Bound(LRoom &lroom, MeshInstance * pMI)
|
||||||
|
{
|
||||||
|
print("\t\tConvert_Bound : " + pMI->get_name());
|
||||||
|
|
||||||
|
// some godot jiggery pokery to get the mesh verts in local space
|
||||||
|
Ref<Mesh> rmesh = pMI->get_mesh();
|
||||||
|
Array arrays = rmesh->surface_get_arrays(0);
|
||||||
|
PoolVector<Vector3> p_vertices = arrays[VS::ARRAY_VERTEX];
|
||||||
|
|
||||||
|
// convert to world space
|
||||||
|
Transform trans = pMI->get_global_transform();
|
||||||
|
Vector<Vector3> points;
|
||||||
|
for (int n=0; n<p_vertices.size(); n++)
|
||||||
|
{
|
||||||
|
Vector3 ptWorld = trans.xform(p_vertices[n]);
|
||||||
|
points.push_back(ptWorld);
|
||||||
|
|
||||||
|
// expand the room AABB to make sure it encompasses the bound
|
||||||
|
lroom.m_AABB.expand_to(ptWorld);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (points.size() > 3)
|
||||||
|
{
|
||||||
|
Geometry::MeshData md;
|
||||||
|
Error err = QuickHull::build(points, md);
|
||||||
|
if (err == OK)
|
||||||
|
{
|
||||||
|
// get the planes
|
||||||
|
for (int n=0; n<md.faces.size(); n++)
|
||||||
|
{
|
||||||
|
const Plane &p = md.faces[n].plane;
|
||||||
|
Bound_AddPlaneIfUnique(lroom.m_Bound.m_Planes, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
print("\t\t\tcontained " + itos(lroom.m_Bound.m_Planes.size()) + " planes.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LRoomConverter::Convert_Bounds()
|
||||||
|
{
|
||||||
|
for (int n=0; n<LMAN->m_Rooms.size(); n++)
|
||||||
|
{
|
||||||
|
LRoom &lroom = LMAN->m_Rooms[n];
|
||||||
|
|
||||||
|
//print("DetectBounds from room " + lroom.get_name());
|
||||||
|
|
||||||
|
Spatial * pGRoom = lroom.GetGodotRoom();
|
||||||
|
assert (pGRoom);
|
||||||
|
|
||||||
|
|
||||||
|
for (int n=0; n<pGRoom->get_child_count(); n++)
|
||||||
|
{
|
||||||
|
Node * pChild = pGRoom->get_child(n);
|
||||||
|
|
||||||
|
if (Node_IsBound(pChild))
|
||||||
|
{
|
||||||
|
MeshInstance * pMesh = Object::cast_to<MeshInstance>(pChild);
|
||||||
|
assert (pMesh);
|
||||||
|
Convert_Bound(lroom, pMesh);
|
||||||
|
|
||||||
|
// delete the mesh
|
||||||
|
pGRoom->remove_child(pChild);
|
||||||
|
pChild->queue_delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void LRoomConverter::Convert_Portals()
|
void LRoomConverter::Convert_Portals()
|
||||||
{
|
{
|
||||||
for (int pass=0; pass<3; pass++)
|
for (int pass=0; pass<3; pass++)
|
||||||
@ -228,16 +348,16 @@ void LRoomConverter::LRoom_DetectPortalMeshes(LRoom &lroom, LTempRoom &troom)
|
|||||||
{
|
{
|
||||||
Node * pChild = pGRoom->get_child(n);
|
Node * pChild = pGRoom->get_child(n);
|
||||||
|
|
||||||
MeshInstance * pMesh = Object::cast_to<MeshInstance>(pChild);
|
if (Node_IsPortal(pChild))
|
||||||
if (pMesh)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
|
MeshInstance * pMesh = Object::cast_to<MeshInstance>(pChild);
|
||||||
|
assert (pMesh);
|
||||||
|
|
||||||
// name must start with 'portal_'
|
// name must start with 'portal_'
|
||||||
// and ends with the name of the room we want to link to (without the 'room_')
|
// and ends with the name of the room we want to link to (without the 'room_')
|
||||||
if (LPortal::NameStartsWith(pMesh, "portal_"))
|
String szLinkRoom = LPortal::FindNameAfter(pMesh, "portal_");
|
||||||
{
|
LRoom_DetectedPortalMesh(lroom, troom, pMesh, szLinkRoom);
|
||||||
String szLinkRoom = LPortal::FindNameAfter(pMesh, "portal_");
|
|
||||||
LRoom_DetectedPortalMesh(lroom, troom, pMesh, szLinkRoom);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,20 +372,14 @@ void LRoomConverter::LRoom_DetectPortalMeshes(LRoom &lroom, LTempRoom &troom)
|
|||||||
{
|
{
|
||||||
Node * pChild = pGRoom->get_child(n);
|
Node * pChild = pGRoom->get_child(n);
|
||||||
|
|
||||||
MeshInstance * pMesh = Object::cast_to<MeshInstance>(pChild);
|
if (Node_IsPortal(pChild))
|
||||||
if (pMesh)
|
|
||||||
{
|
{
|
||||||
// name must start with 'portal_'
|
// delete the original child, as it is no longer needed at runtime (except maybe for debugging .. NYI?)
|
||||||
// and ends with the name of the room we want to link to (without the 'room_')
|
// pMeshInstance->hide();
|
||||||
if (LPortal::NameStartsWith(pMesh, "portal_"))
|
pChild->get_parent()->remove_child(pChild);
|
||||||
{
|
pChild->queue_delete();
|
||||||
// delete the original child, as it is no longer needed at runtime (except maybe for debugging .. NYI?)
|
|
||||||
// pMeshInstance->hide();
|
|
||||||
pMesh->get_parent()->remove_child(pMesh);
|
|
||||||
pMesh->queue_delete();
|
|
||||||
|
|
||||||
bDetectedOne = true;
|
bDetectedOne = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bDetectedOne)
|
if (bDetectedOne)
|
||||||
@ -350,7 +464,7 @@ void LRoomConverter::LRoom_MakePortalsTwoWay(LRoom &lroom, LTempRoom &troom, int
|
|||||||
print("\t\tcreating opposite portal");
|
print("\t\tcreating opposite portal");
|
||||||
|
|
||||||
// get the temproom this portal is linking to
|
// get the temproom this portal is linking to
|
||||||
LTempRoom &nroom = m_TempRooms[portal_orig.m_iRoomNum];
|
//LTempRoom &nroom = m_TempRooms[portal_orig.m_iRoomNum];
|
||||||
|
|
||||||
// does a portal already exist back to the orig room?
|
// does a portal already exist back to the orig room?
|
||||||
// NOTE this doesn't cope with multiple portals between pairs of rooms yet.
|
// NOTE this doesn't cope with multiple portals between pairs of rooms yet.
|
||||||
@ -405,6 +519,38 @@ bool LRoomConverter::Node_IsRoom(Node * pNode) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LRoomConverter::Node_IsIgnore(Node * pNode) const
|
||||||
|
{
|
||||||
|
if (LPortal::NameStartsWith(pNode, "ignore_"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LRoomConverter::Node_IsBound(Node * pNode) const
|
||||||
|
{
|
||||||
|
MeshInstance * pMI = Object::cast_to<MeshInstance>(pNode);
|
||||||
|
if (!pMI)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (LPortal::NameStartsWith(pMI, "bound_"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LRoomConverter::Node_IsPortal(Node * pNode) const
|
||||||
|
{
|
||||||
|
MeshInstance * pMI = Object::cast_to<MeshInstance>(pNode);
|
||||||
|
if (!pMI)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (LPortal::NameStartsWith(pMI, "portal_"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// keep the global namespace clean
|
// keep the global namespace clean
|
||||||
|
@ -66,6 +66,8 @@ private:
|
|||||||
void Convert_Room_FindObjects_Recursive(Node * pParent, LRoom &lroom, LAABB &bb_room);
|
void Convert_Room_FindObjects_Recursive(Node * pParent, LRoom &lroom, LAABB &bb_room);
|
||||||
|
|
||||||
void Convert_Portals();
|
void Convert_Portals();
|
||||||
|
void Convert_Bounds();
|
||||||
|
bool Convert_Bound(LRoom &lroom, MeshInstance * pMI);
|
||||||
|
|
||||||
|
|
||||||
void LRoom_DetectPortalMeshes(LRoom &lroom, LTempRoom &troom);
|
void LRoom_DetectPortalMeshes(LRoom &lroom, LTempRoom &troom);
|
||||||
@ -79,12 +81,20 @@ private:
|
|||||||
|
|
||||||
// helper
|
// helper
|
||||||
bool Node_IsRoom(Node * pNode) const;
|
bool Node_IsRoom(Node * pNode) const;
|
||||||
|
bool Node_IsPortal(Node * pNode) const;
|
||||||
|
bool Node_IsBound(Node * pNode) const;
|
||||||
|
bool Node_IsIgnore(Node * pNode) const;
|
||||||
|
|
||||||
int FindRoom_ByName(String szName) const;
|
int FindRoom_ByName(String szName) const;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
LRoomManager * m_pManager;
|
LRoomManager * m_pManager;
|
||||||
LVector<LTempRoom> m_TempRooms;
|
LVector<LTempRoom> m_TempRooms;
|
||||||
|
|
||||||
|
bool Bound_AddPlaneIfUnique(LVector<Plane> &planes, const Plane &p);
|
||||||
|
|
||||||
static void print(String sz);
|
static void print(String sz);
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -36,10 +36,15 @@ LRoomManager::LRoomManager()
|
|||||||
|
|
||||||
int LRoomManager::FindClosestRoom(const Vector3 &pt) const
|
int LRoomManager::FindClosestRoom(const Vector3 &pt) const
|
||||||
{
|
{
|
||||||
|
|
||||||
//print_line("FindClosestRoom");
|
//print_line("FindClosestRoom");
|
||||||
int closest = -1;
|
int closest = -1;
|
||||||
float closest_dist = FLT_MAX;
|
float closest_dist = FLT_MAX;
|
||||||
|
|
||||||
|
// uses bounds if this is available
|
||||||
|
int closest_within = -1;
|
||||||
|
float within_dist = FLT_MAX;
|
||||||
|
|
||||||
for (int n=0; n<m_Rooms.size(); n++)
|
for (int n=0; n<m_Rooms.size(); n++)
|
||||||
{
|
{
|
||||||
const LRoom &lroom = m_Rooms[n];
|
const LRoom &lroom = m_Rooms[n];
|
||||||
@ -51,8 +56,33 @@ int LRoomManager::FindClosestRoom(const Vector3 &pt) const
|
|||||||
closest = n;
|
closest = n;
|
||||||
closest_dist = d;
|
closest_dist = d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// is there a bound?
|
||||||
|
if (lroom.m_Bound.IsActive())
|
||||||
|
{
|
||||||
|
// is it within the aabb?
|
||||||
|
if (lroom.m_AABB.has_point(pt))
|
||||||
|
{
|
||||||
|
// is it within the convex hull?
|
||||||
|
float dist = lroom.m_Bound.GetClosestDistance(pt);
|
||||||
|
|
||||||
|
// find the lowest within distance of the nearby room convex hulls
|
||||||
|
if (dist < within_dist)
|
||||||
|
{
|
||||||
|
closest_within = n;
|
||||||
|
within_dist = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// some logic whether to use the hulls or the closest dist
|
||||||
|
if (within_dist < 1.0f)
|
||||||
|
{
|
||||||
|
return closest_within;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return closest;
|
return closest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user