mirror of
https://github.com/Relintai/godot-lportal.git
synced 2024-11-11 10:52:09 +01:00
Refactor LRooms and LPortals to no longer be part of scene graph
This commit is contained in:
parent
9fbdfe2bf9
commit
56e785ab4b
3
SCsub
3
SCsub
@ -5,6 +5,7 @@ sources = [
|
|||||||
"register_types.cpp",
|
"register_types.cpp",
|
||||||
"lroom.cpp",
|
"lroom.cpp",
|
||||||
"lroom_manager.cpp",
|
"lroom_manager.cpp",
|
||||||
|
"lroom_converter.cpp",
|
||||||
"lportal.cpp",
|
"lportal.cpp",
|
||||||
"lplanes_pool.cpp",
|
"lplanes_pool.cpp",
|
||||||
"ldob.cpp",
|
"ldob.cpp",
|
||||||
@ -12,7 +13,7 @@ sources = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
module_env = env.Clone()
|
module_env = env.Clone()
|
||||||
module_env.Append(CXXFLAGS=['-O2', '-std=c++11'])
|
module_env.Append(CXXFLAGS=['-O2', '-std=c++11', '-Wno-sign-compare', '-Wno-strict-aliasing'])
|
||||||
|
|
||||||
if ARGUMENTS.get('lportal_shared', 'no') == 'yes':
|
if ARGUMENTS.get('lportal_shared', 'no') == 'yes':
|
||||||
# Shared lib compilation
|
# Shared lib compilation
|
||||||
|
10
ldob.h
10
ldob.h
@ -2,6 +2,16 @@
|
|||||||
|
|
||||||
#include "scene/3d/spatial.h"
|
#include "scene/3d/spatial.h"
|
||||||
|
|
||||||
|
|
||||||
|
// static object
|
||||||
|
class LSob
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ObjectID m_ID; // godot object
|
||||||
|
AABB m_aabb; // world space
|
||||||
|
};
|
||||||
|
|
||||||
|
// dynamic object
|
||||||
class LDob
|
class LDob
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
178
lportal.cpp
178
lportal.cpp
@ -126,86 +126,31 @@ LPortal::eClipResult LPortal::ClipWithPlane(const Plane &p) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LPortal::CreateGeometry(PoolVector<Vector3> p_vertices, const Transform &trans)
|
||||||
|
|
||||||
// use the name of the portal to find a room to link to
|
|
||||||
void LPortal::Link(LRoom * pParentRoom)
|
|
||||||
{
|
|
||||||
// should start with 'portal_'
|
|
||||||
if (!NameStartsWith(this, "lportal_"))
|
|
||||||
{
|
|
||||||
WARN_PRINT("Portal name should begin with lportal_");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String szRoom = FindNameAfter(this, "lportal_");
|
|
||||||
|
|
||||||
print("LPortal::Link to room " + szRoom);
|
|
||||||
|
|
||||||
// find the room group
|
|
||||||
Spatial * pGroup = Object::cast_to<Spatial>(pParentRoom->get_parent());
|
|
||||||
if (!pGroup)
|
|
||||||
{
|
|
||||||
WARN_PRINT("Room parent is not a spatial");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// attempt to find a child of the group that has the name specified
|
|
||||||
int nChildren = pGroup->get_child_count();
|
|
||||||
|
|
||||||
for (int n=0; n<nChildren; n++)
|
|
||||||
{
|
|
||||||
Node * pChild = pGroup->get_child(n);
|
|
||||||
|
|
||||||
String szChildName = pChild->get_name();
|
|
||||||
|
|
||||||
// is the name correct for the desired room?
|
|
||||||
if (szRoom != szChildName)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
LRoom * pTargetRoom = Object::cast_to<LRoom>(pChild);
|
|
||||||
|
|
||||||
if (!pTargetRoom)
|
|
||||||
{
|
|
||||||
WARN_PRINT("Portal target is not a room");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// found! link
|
|
||||||
pTargetRoom->MakeOppositePortal(this, pParentRoom);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void LPortal::CreateGeometry(PoolVector<Vector3> p_vertices)
|
|
||||||
{
|
{
|
||||||
int nPoints = p_vertices.size();
|
int nPoints = p_vertices.size();
|
||||||
ERR_FAIL_COND(nPoints < 3);
|
ERR_FAIL_COND(nPoints < 3);
|
||||||
|
|
||||||
m_ptsLocal.resize(nPoints);
|
|
||||||
m_ptsWorld.resize(nPoints);
|
m_ptsWorld.resize(nPoints);
|
||||||
|
|
||||||
print("\tLPortal::CreateGeometry nPoints : " + itos(nPoints));
|
print("\tLPortal::CreateGeometry nPoints : " + itos(nPoints));
|
||||||
|
|
||||||
for (int n=0; n<nPoints; n++)
|
for (int n=0; n<nPoints; n++)
|
||||||
{
|
{
|
||||||
m_ptsLocal.set(n, p_vertices[n]);
|
Vector3 ptWorld = trans.xform(p_vertices[n]);
|
||||||
Variant pt = p_vertices[n];
|
m_ptsWorld.set(n, ptWorld);
|
||||||
print("\t\t" + itos(n) + "\t: " + pt);
|
|
||||||
|
print("\t\t" + itos(n) + "\tLocal : " + Variant(p_vertices[n]) + "\tWorld : " + ptWorld);
|
||||||
}
|
}
|
||||||
|
|
||||||
SortVertsClockwise();
|
SortVertsClockwise();
|
||||||
|
|
||||||
CalculateWorldPoints();
|
|
||||||
|
|
||||||
PlaneFromPoints();
|
PlaneFromPoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
// assume first 3 determine the desired normal
|
// assume first 3 determine the desired normal
|
||||||
void LPortal::SortVertsClockwise()
|
void LPortal::SortVertsClockwise()
|
||||||
{
|
{
|
||||||
Vector<Vector3> &verts = m_ptsLocal;
|
Vector<Vector3> &verts = m_ptsWorld;
|
||||||
|
|
||||||
// find normal
|
// find normal
|
||||||
Plane plane = Plane(verts[0], verts[1], verts[2]);
|
Plane plane = Plane(verts[0], verts[1], verts[2]);
|
||||||
@ -237,9 +182,8 @@ void LPortal::SortVertsClockwise()
|
|||||||
for (int m=n+1; m<nPoints; m++)
|
for (int m=n+1; m<nPoints; m++)
|
||||||
{
|
{
|
||||||
if (p.distance_to(verts[m]) > 0.0f)
|
if (p.distance_to(verts[m]) > 0.0f)
|
||||||
// if (p.WhichSideNDLCompatible(m_Verts[m], 0.0f) != CoPlane::NEGATIVE_SIDE)
|
|
||||||
{
|
{
|
||||||
Vector3 b = m_ptsLocal[m] - ptCentre;
|
Vector3 b = verts[m] - ptCentre;
|
||||||
b.normalize();
|
b.normalize();
|
||||||
|
|
||||||
double Angle = a.dot(b);
|
double Angle = a.dot(b);
|
||||||
@ -278,7 +222,7 @@ void LPortal::SortVertsClockwise()
|
|||||||
|
|
||||||
void LPortal::ReverseWindingOrder()
|
void LPortal::ReverseWindingOrder()
|
||||||
{
|
{
|
||||||
Vector<Vector3> &verts = m_ptsLocal;
|
Vector<Vector3> &verts = m_ptsWorld;
|
||||||
Vector<Vector3> copy = verts;
|
Vector<Vector3> copy = verts;
|
||||||
|
|
||||||
for (int n=0; n<verts.size(); n++)
|
for (int n=0; n<verts.size(); n++)
|
||||||
@ -289,57 +233,20 @@ void LPortal::ReverseWindingOrder()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// local from world and local transform
|
|
||||||
void LPortal::CalculateLocalPoints()
|
|
||||||
{
|
|
||||||
int nPoints = m_ptsLocal.size();
|
|
||||||
ERR_FAIL_COND(m_ptsLocal.size() != m_ptsWorld.size());
|
|
||||||
|
|
||||||
Transform tr = get_transform();
|
|
||||||
|
|
||||||
print("\tCalculateLocalPoints");
|
|
||||||
for (int n=0; n<nPoints; n++)
|
|
||||||
{
|
|
||||||
m_ptsLocal.set(n, tr.xform_inv(m_ptsWorld[n]));
|
|
||||||
Variant pt = m_ptsLocal[n];
|
|
||||||
print("\t\t" + itos(n) + "\t: " + pt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// world from local and transform
|
|
||||||
void LPortal::CalculateWorldPoints()
|
|
||||||
{
|
|
||||||
int nPoints = m_ptsLocal.size();
|
|
||||||
ERR_FAIL_COND(m_ptsLocal.size() != m_ptsWorld.size());
|
|
||||||
|
|
||||||
Transform tr = get_global_transform();
|
|
||||||
|
|
||||||
print("\tCalculateWorldPoints");
|
|
||||||
for (int n=0; n<nPoints; n++)
|
|
||||||
{
|
|
||||||
m_ptsWorld.set(n, tr.xform(m_ptsLocal[n]));
|
|
||||||
Variant pt = m_ptsWorld[n];
|
|
||||||
print("\t\t" + itos(n) + "\t: " + pt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LPortal::CopyReversedGeometry(const LPortal &source)
|
void LPortal::CopyReversedGeometry(const LPortal &source)
|
||||||
{
|
{
|
||||||
print("CopyReversedGeometry");
|
print("CopyReversedGeometry");
|
||||||
// points are the same but reverse winding order
|
// points are the same but reverse winding order
|
||||||
int nPoints = source.m_ptsWorld.size();
|
int nPoints = source.m_ptsWorld.size();
|
||||||
|
|
||||||
m_ptsLocal.resize(nPoints);
|
|
||||||
m_ptsWorld.resize(nPoints);
|
m_ptsWorld.resize(nPoints);
|
||||||
|
|
||||||
for (int n=0; n<nPoints; n++)
|
for (int n=0; n<nPoints; n++)
|
||||||
{
|
{
|
||||||
m_ptsWorld.set(n, source.m_ptsWorld[nPoints - n - 1]);
|
m_ptsWorld.set(n, source.m_ptsWorld[nPoints - n - 1]);
|
||||||
Variant pt = m_ptsWorld[n];
|
print("\t\t" + itos(n) + "\t: " + Variant(m_ptsWorld[n]));
|
||||||
print("\t\t" + itos(n) + "\t: " + pt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CalculateLocalPoints();
|
|
||||||
PlaneFromPoints();
|
PlaneFromPoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,77 +262,12 @@ void LPortal::PlaneFromPoints()
|
|||||||
|
|
||||||
print("Plane normal world space : " + m_Plane);
|
print("Plane normal world space : " + m_Plane);
|
||||||
|
|
||||||
// Plane opp = Plane(m_ptsWorld[2], m_ptsWorld[1], m_ptsWorld[0]);
|
|
||||||
// print_line("Plane opposite : " + opp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool LPortal::AddRoom(NodePath path)
|
|
||||||
{
|
|
||||||
print("LPortal::AddRoom path is " + path);
|
|
||||||
|
|
||||||
if (has_node(path))
|
|
||||||
{
|
|
||||||
LRoom * pNode = Object::cast_to<LRoom>(get_node(path));
|
|
||||||
if (pNode)
|
|
||||||
{
|
|
||||||
ObjectID id = pNode->get_instance_id();
|
|
||||||
|
|
||||||
m_room_path = path;
|
|
||||||
m_room_ID = id;
|
|
||||||
|
|
||||||
// make the portal name correct and feature the room name
|
|
||||||
int num_names = path.get_name_count();
|
|
||||||
if (num_names < 1)
|
|
||||||
{
|
|
||||||
WARN_PRINT("LPortal::AddRoom : Path too short");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String szRoom = path.get_name(num_names-1);
|
|
||||||
|
|
||||||
String szPortal = "lportal_" + szRoom;
|
|
||||||
set_name(szPortal);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WARN_PRINT("not a room");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WARN_PRINTS("portal link room not found : " + path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPortal::LPortal() {
|
LPortal::LPortal() {
|
||||||
// unset
|
// unset
|
||||||
m_room_ID = 0;
|
m_iRoomNum = -1;
|
||||||
}
|
|
||||||
|
|
||||||
LRoom * LPortal::GetLinkedRoom() const
|
|
||||||
{
|
|
||||||
Object *pObj = ObjectDB::get_instance(m_room_ID);
|
|
||||||
|
|
||||||
if (!pObj)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
LRoom * pRoom = Object::cast_to<LRoom>(pObj);
|
|
||||||
if (!pRoom)
|
|
||||||
{
|
|
||||||
WARN_PRINT_ONCE("LRoomManager::FrameUpdate : curr room is not an LRoom");
|
|
||||||
}
|
|
||||||
|
|
||||||
return pRoom;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void LPortal::_bind_methods() {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
37
lportal.h
37
lportal.h
@ -32,12 +32,8 @@
|
|||||||
|
|
||||||
class LRoom;
|
class LRoom;
|
||||||
|
|
||||||
class LPortal : public Spatial {
|
class LPortal {
|
||||||
GDCLASS(LPortal, Spatial);
|
public:
|
||||||
|
|
||||||
friend class LRoom;
|
|
||||||
friend class LRoomManager;
|
|
||||||
private:
|
|
||||||
|
|
||||||
enum eClipResult
|
enum eClipResult
|
||||||
{
|
{
|
||||||
@ -47,46 +43,31 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
ObjectID m_room_ID;
|
const String &get_name() const {return m_szName;}
|
||||||
NodePath m_room_path;
|
|
||||||
|
|
||||||
protected:
|
// linked room, this is the number not godot ID
|
||||||
static void _bind_methods();
|
int m_iRoomNum;
|
||||||
|
String m_szName;
|
||||||
|
|
||||||
LPortal::eClipResult ClipWithPlane(const Plane &p) const;
|
LPortal::eClipResult ClipWithPlane(const Plane &p) const;
|
||||||
void AddPlanes(const Vector3 &ptCam, LVector<Plane> &planes) const;
|
void AddPlanes(const Vector3 &ptCam, LVector<Plane> &planes) const;
|
||||||
|
|
||||||
public:
|
|
||||||
// normal determined by winding order
|
// normal determined by winding order
|
||||||
Vector<Vector3> m_ptsWorld;
|
Vector<Vector3> m_ptsWorld;
|
||||||
Vector<Vector3> m_ptsLocal;
|
|
||||||
Plane m_Plane;
|
Plane m_Plane;
|
||||||
|
|
||||||
|
|
||||||
ObjectID GetLinkedRoomID() const {return m_room_ID;}
|
|
||||||
LRoom * GetLinkedRoom() const;
|
|
||||||
|
|
||||||
LPortal();
|
LPortal();
|
||||||
|
|
||||||
private:
|
|
||||||
// use the name of the portal to find a room to link to
|
|
||||||
void Link(LRoom * pParentRoom);
|
|
||||||
bool AddRoom(NodePath path);
|
|
||||||
void CopyReversedGeometry(const LPortal &source);
|
void CopyReversedGeometry(const LPortal &source);
|
||||||
void CreateGeometry(PoolVector<Vector3> p_vertices);
|
void CreateGeometry(PoolVector<Vector3> p_vertices, const Transform &trans);
|
||||||
void PlaneFromPoints();
|
void PlaneFromPoints();
|
||||||
|
|
||||||
void CalculateWorldPoints();
|
|
||||||
void CalculateLocalPoints();
|
|
||||||
|
|
||||||
void SortVertsClockwise();
|
void SortVertsClockwise();
|
||||||
void ReverseWindingOrder();
|
void ReverseWindingOrder();
|
||||||
public:
|
|
||||||
// useful funcs
|
// useful funcs
|
||||||
static bool NameStartsWith(Node * pNode, String szSearch);
|
static bool NameStartsWith(Node * pNode, String szSearch);
|
||||||
static String FindNameAfter(Node * pNode, String szStart);
|
static String FindNameAfter(Node * pNode, String szStart);
|
||||||
static void print(String sz);
|
static void print(String sz);
|
||||||
protected:
|
|
||||||
static bool m_bRunning;
|
static bool m_bRunning;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
311
lroom.cpp
311
lroom.cpp
@ -27,13 +27,27 @@
|
|||||||
|
|
||||||
void LRoom::print(String sz)
|
void LRoom::print(String sz)
|
||||||
{
|
{
|
||||||
// print_line(sz);
|
|
||||||
LPortal::print(sz);
|
LPortal::print(sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
LRoom::LRoom() {
|
LRoom::LRoom() {
|
||||||
m_LocalRoomID = -1;
|
m_RoomID = -1;
|
||||||
m_uiFrameTouched = 0;
|
m_uiFrameTouched = 0;
|
||||||
|
m_iFirstPortal = 0;
|
||||||
|
m_iNumPortals = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Spatial * LRoom::GetGodotRoom() const
|
||||||
|
{
|
||||||
|
Object *pObj = ObjectDB::get_instance(m_GodotID);
|
||||||
|
|
||||||
|
// assuming is a portal
|
||||||
|
Spatial * pSpat = Object::cast_to<Spatial>(pObj);
|
||||||
|
|
||||||
|
return pSpat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -63,8 +77,8 @@ bool LRoom::RemoveDOB(Node * pDOB)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// returns -1 if no change, or the objectID of the linked room
|
// returns -1 if no change, or the linked room we are moving into
|
||||||
LRoom * LRoom::UpdateDOB(Spatial * pDOB)
|
LRoom * LRoom::UpdateDOB(LRoomManager &manager, Spatial * pDOB)
|
||||||
{
|
{
|
||||||
const Vector3 &pt = pDOB->get_global_transform().origin;
|
const Vector3 &pt = pDOB->get_global_transform().origin;
|
||||||
|
|
||||||
@ -76,114 +90,26 @@ LRoom * LRoom::UpdateDOB(Spatial * pDOB)
|
|||||||
// slop = 0.0f;
|
// slop = 0.0f;
|
||||||
|
|
||||||
// check each portal - has the object crossed it into the neighbouring room?
|
// check each portal - has the object crossed it into the neighbouring room?
|
||||||
int nPortals = m_portal_IDs.size();
|
for (int p=0; p<m_iNumPortals; p++)
|
||||||
for (int p=0; p<nPortals; p++)
|
|
||||||
{
|
{
|
||||||
ObjectID id = m_portal_IDs[p];
|
const LPortal &port = manager.m_Portals[m_iFirstPortal + p];
|
||||||
|
|
||||||
// get the portal
|
float dist = port.m_Plane.distance_to(pt);
|
||||||
Object *pObj = ObjectDB::get_instance(id);
|
|
||||||
|
|
||||||
// assuming is a portal
|
|
||||||
LPortal * pPortal = Object::cast_to<LPortal>(pObj);
|
|
||||||
|
|
||||||
if (!pPortal)
|
|
||||||
{
|
|
||||||
WARN_PRINT_ONCE("LRoom::UpdateDynamicObject : Not a portal");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
float dist = pPortal->m_Plane.distance_to(pt);
|
|
||||||
|
|
||||||
if (dist > slop)
|
if (dist > slop)
|
||||||
{
|
{
|
||||||
print("DOB at pos " + pt + " ahead of portal " + pPortal->get_name() + " by " + String(Variant(dist)));
|
print("DOB at pos " + pt + " ahead of portal " + port.get_name() + " by " + String(Variant(dist)));
|
||||||
|
|
||||||
// move into the adjoining room
|
// we want to move into the adjoining room
|
||||||
return pPortal->GetLinkedRoom();
|
return &manager.Portal_GetLinkedRoom(port);
|
||||||
|
|
||||||
// LRoom * pNewRoom = pPortal->GetLinkedRoom();
|
|
||||||
// if (pNewRoom)
|
|
||||||
// {
|
|
||||||
// // detach from this room and add to the new room
|
|
||||||
// remove_child(pDynObj);
|
|
||||||
// pNewRoom->add_child(pDynObj);
|
|
||||||
// // only allow one transition per frame
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// WARN_PRINT_ONCE("LRoom::UpdateDynamicObject : portal linked room is NULL");
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// assumes that the object is within, or just outside the bounds of the room...
|
|
||||||
// if not the results will be 'interesting'.
|
|
||||||
// Works simply by detecting crossing portals
|
|
||||||
bool LRoom::UpdateDynamicObject(Node * pDynObj)
|
|
||||||
{
|
|
||||||
Spatial * pSpatial = Object::cast_to<Spatial>(pDynObj);
|
|
||||||
if (!pSpatial)
|
|
||||||
{
|
|
||||||
WARN_PRINT_ONCE("LRoom::UpdateDynamicObject : object is not a spatial");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Vector3 &pt = pSpatial->get_global_transform().origin;
|
void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, const LCamera &cam, const LVector<Plane> &planes, int portalID_from)
|
||||||
|
|
||||||
const float slop = 0.2f;
|
|
||||||
|
|
||||||
// check each portal - has the object crossed it into the neighbouring room?
|
|
||||||
int nPortals = m_portal_IDs.size();
|
|
||||||
for (int p=0; p<nPortals; p++)
|
|
||||||
{
|
|
||||||
ObjectID id = m_portal_IDs[p];
|
|
||||||
|
|
||||||
// get the portal
|
|
||||||
Object *pObj = ObjectDB::get_instance(id);
|
|
||||||
|
|
||||||
// assuming is a portal
|
|
||||||
LPortal * pPortal = Object::cast_to<LPortal>(pObj);
|
|
||||||
|
|
||||||
if (!pPortal)
|
|
||||||
{
|
|
||||||
WARN_PRINT_ONCE("LRoom::UpdateDynamicObject : Not a portal");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
float dist = pPortal->m_Plane.distance_to(pt);
|
|
||||||
|
|
||||||
if (dist > slop)
|
|
||||||
{
|
|
||||||
print("DOB at pos " + pt + " ahead of portal " + pPortal->get_name() + " by " + String(Variant(dist)));
|
|
||||||
|
|
||||||
// move into the adjoining room
|
|
||||||
LRoom * pNewRoom = pPortal->GetLinkedRoom();
|
|
||||||
if (pNewRoom)
|
|
||||||
{
|
|
||||||
// detach from this room and add to the new room
|
|
||||||
remove_child(pDynObj);
|
|
||||||
pNewRoom->add_child(pDynObj);
|
|
||||||
// only allow one transition per frame
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WARN_PRINT_ONCE("LRoom::UpdateDynamicObject : portal linked room is NULL");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, const LCamera &cam, const LVector<Plane> &planes, Lawn::LBitField_Dynamic &BF_visible, ObjectID portalID_from)
|
|
||||||
{
|
{
|
||||||
// prevent too much depth
|
// prevent too much depth
|
||||||
if (depth >= 8)
|
if (depth >= 8)
|
||||||
@ -199,19 +125,18 @@ void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, cons
|
|||||||
m_uiFrameTouched = manager.m_uiFrameCounter;
|
m_uiFrameTouched = manager.m_uiFrameCounter;
|
||||||
|
|
||||||
// show this room and add to visible list of rooms
|
// show this room and add to visible list of rooms
|
||||||
show();
|
GetGodotRoom()->show();
|
||||||
BF_visible.SetBit(m_LocalRoomID, true);
|
manager.m_BF_visible_rooms.SetBit(m_RoomID, true);
|
||||||
|
|
||||||
// clip all objects in this room to the clipping planes
|
// clip all objects in this room to the clipping planes
|
||||||
for (int n=0; n<get_child_count(); n++)
|
for (int n=0; n<m_SOBs.size(); n++)
|
||||||
{
|
{
|
||||||
// ignore portals
|
const LSob sob = m_SOBs[n];
|
||||||
Node * pNode = get_child(n);
|
Object * pNode = ObjectDB::get_instance(sob.m_ID);
|
||||||
LPortal * pPortal = Object::cast_to<LPortal>(pNode);
|
|
||||||
if (pPortal)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
VisualInstance * pObj = Object::cast_to<VisualInstance>(pNode);
|
VisualInstance * pObj = Object::cast_to<VisualInstance>(pNode);
|
||||||
|
|
||||||
|
// should always be a visual instance, only these are added as SOBs
|
||||||
if (pObj)
|
if (pObj)
|
||||||
{
|
{
|
||||||
//Vector3 pt = pObj->get_global_transform().origin;
|
//Vector3 pt = pObj->get_global_transform().origin;
|
||||||
@ -251,36 +176,20 @@ void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (int p=0; p<m_iNumPortals; p++)
|
||||||
|
|
||||||
// go through each portal out of here
|
|
||||||
int nPortals = m_portal_IDs.size();
|
|
||||||
|
|
||||||
// ObjectID this_room_id = get_instance_id();
|
|
||||||
|
|
||||||
for (int p=0; p<nPortals; p++)
|
|
||||||
{
|
{
|
||||||
ObjectID id = m_portal_IDs[p];
|
int port_id = m_iFirstPortal + p;
|
||||||
|
|
||||||
// ignore if the portal we are looking in from
|
// ignore if the portal we are looking in from
|
||||||
if (id == portalID_from)
|
if (port_id == portalID_from)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// get the portal
|
const LPortal &port = manager.m_Portals[port_id];
|
||||||
Object *pObj = ObjectDB::get_instance(id);
|
|
||||||
|
|
||||||
// assuming is a portal
|
|
||||||
LPortal * pPortal = Object::cast_to<LPortal>(pObj);
|
|
||||||
|
|
||||||
if (!pPortal)
|
|
||||||
{
|
|
||||||
WARN_PRINT_ONCE("LRoom::DetermineVisibility_Recursive : Not a portal");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// have we already handled the room on this frame?
|
// have we already handled the room on this frame?
|
||||||
// get the room pointed to by the portal
|
// get the room pointed to by the portal
|
||||||
LRoom * pLinkedRoom = pPortal->GetLinkedRoom();
|
LRoom * pLinkedRoom = &manager.Portal_GetLinkedRoom(port);
|
||||||
|
|
||||||
if (pLinkedRoom->m_uiFrameTouched == manager.m_uiFrameCounter)
|
if (pLinkedRoom->m_uiFrameTouched == manager.m_uiFrameCounter)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -305,7 +214,7 @@ void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, cons
|
|||||||
// If it isn't we would need a different strategy
|
// If it isn't we would need a different strategy
|
||||||
for (int l=1; l<planes.size(); l++)
|
for (int l=1; l<planes.size(); l++)
|
||||||
{
|
{
|
||||||
LPortal::eClipResult res = pPortal->ClipWithPlane(planes[l]);
|
LPortal::eClipResult res = port.ClipWithPlane(planes[l]);
|
||||||
|
|
||||||
switch (res)
|
switch (res)
|
||||||
{
|
{
|
||||||
@ -339,152 +248,24 @@ void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, cons
|
|||||||
new_planes.copy_from(planes);
|
new_planes.copy_from(planes);
|
||||||
|
|
||||||
// add the planes for the portal
|
// add the planes for the portal
|
||||||
pPortal->AddPlanes(cam.m_ptPos, new_planes);
|
port.AddPlanes(cam.m_ptPos, new_planes);
|
||||||
|
|
||||||
if (pLinkedRoom)
|
if (pLinkedRoom)
|
||||||
pLinkedRoom->DetermineVisibility_Recursive(manager, depth + 1, cam, new_planes, BF_visible, id);
|
pLinkedRoom->DetermineVisibility_Recursive(manager, depth + 1, cam, new_planes, port_id);
|
||||||
|
|
||||||
|
// we no longer need these planes
|
||||||
manager.m_Pool.Free(uiPoolMem);
|
manager.m_Pool.Free(uiPoolMem);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// planes pool is empty!
|
// planes pool is empty!
|
||||||
|
// This will happen if the view goes through shedloads of portals
|
||||||
|
// The solution is either to increase the plane pool size, or build levels
|
||||||
|
// with views through multiple portals. Looking through multiple portals is likely to be
|
||||||
|
// slow anyway because of the number of planes to test.
|
||||||
WARN_PRINT_ONCE("Planes pool is empty");
|
WARN_PRINT_ONCE("Planes pool is empty");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// initial setup, allows importing portals as meshes from modelling program,
|
|
||||||
// which will be auto converted to LPortals with this method
|
|
||||||
void LRoom::DetectPortalMeshes()
|
|
||||||
{
|
|
||||||
print("DetectPortalMeshes");
|
|
||||||
|
|
||||||
bool bFoundOne = true;
|
|
||||||
|
|
||||||
while (bFoundOne)
|
|
||||||
{
|
|
||||||
bFoundOne = false;
|
|
||||||
|
|
||||||
for (int n=0; n<get_child_count(); n++)
|
|
||||||
{
|
|
||||||
Node * pChild = get_child(n);
|
|
||||||
|
|
||||||
MeshInstance * pMesh = Object::cast_to<MeshInstance>(pChild);
|
|
||||||
if (pMesh)
|
|
||||||
{
|
|
||||||
// name must start with portal_
|
|
||||||
if (LPortal::NameStartsWith(pMesh, "portal_"))
|
|
||||||
{
|
|
||||||
String szLinkRoom = LPortal::FindNameAfter(pMesh, "portal_");
|
|
||||||
DetectedPortalMesh(pMesh, szLinkRoom);
|
|
||||||
bFoundOne = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bFoundOne)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void LRoom::DetectedPortalMesh(MeshInstance * pMeshInstance, String szLinkRoom)
|
|
||||||
{
|
|
||||||
print("\tDetected PortalMesh");
|
|
||||||
|
|
||||||
Ref<Mesh> rmesh = pMeshInstance->get_mesh();
|
|
||||||
|
|
||||||
Array arrays = rmesh->surface_get_arrays(0);
|
|
||||||
PoolVector<Vector3> p_vertices = arrays[VS::ARRAY_VERTEX];
|
|
||||||
|
|
||||||
LPortal * pNew = memnew(LPortal);
|
|
||||||
pNew->set_name("lportal_");
|
|
||||||
add_child(pNew);
|
|
||||||
|
|
||||||
pNew->set_transform(pMeshInstance->get_transform());
|
|
||||||
|
|
||||||
NodePath temppath = "../../" + szLinkRoom;
|
|
||||||
pNew->AddRoom(temppath);
|
|
||||||
|
|
||||||
// create the portal geometry
|
|
||||||
pNew->CreateGeometry(p_vertices);
|
|
||||||
|
|
||||||
// delete the original child
|
|
||||||
pMeshInstance->get_parent()->remove_child(pMeshInstance);
|
|
||||||
|
|
||||||
pMeshInstance->queue_delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LRoom::MakePortalsTwoWay()
|
|
||||||
{
|
|
||||||
for (int n=0; n<get_child_count(); n++)
|
|
||||||
{
|
|
||||||
Node * pChild = get_child(n);
|
|
||||||
|
|
||||||
LPortal * pPortal = Object::cast_to<LPortal>(pChild);
|
|
||||||
if (pPortal)
|
|
||||||
{
|
|
||||||
pPortal->Link(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// assuming that portals are a child of the room, detect these and make them 2 way
|
|
||||||
void LRoom::MakePortalQuickList()
|
|
||||||
{
|
|
||||||
// this function could be called more than one time...
|
|
||||||
m_portal_IDs.clear();
|
|
||||||
|
|
||||||
for (int n=0; n<get_child_count(); n++)
|
|
||||||
{
|
|
||||||
Node * pChild = get_child(n);
|
|
||||||
|
|
||||||
LPortal * pPortal = Object::cast_to<LPortal>(pChild);
|
|
||||||
if (pPortal)
|
|
||||||
{
|
|
||||||
ObjectID id = pPortal->get_instance_id();
|
|
||||||
m_portal_IDs.push_back(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure there is a back (opposite) portal leading from the portal from to the roomto, from this room
|
|
||||||
void LRoom::MakeOppositePortal(LPortal * pPortalFrom, LRoom * pRoomTo)
|
|
||||||
{
|
|
||||||
ObjectID room_to_id = pRoomTo->get_instance_id();
|
|
||||||
|
|
||||||
// does an opposite portal exist already?
|
|
||||||
for (int n=0; n<get_child_count(); n++)
|
|
||||||
{
|
|
||||||
Node * pChild = get_child(n);
|
|
||||||
|
|
||||||
LPortal * pPortal = Object::cast_to<LPortal>(pChild);
|
|
||||||
if (pPortal)
|
|
||||||
{
|
|
||||||
if (pPortal->GetLinkedRoomID() == room_to_id)
|
|
||||||
// already linked
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we got to here it isn't linked...
|
|
||||||
// add a new portal
|
|
||||||
// NYI
|
|
||||||
LPortal * pNew = memnew(LPortal);
|
|
||||||
pNew->set_name("lportal");
|
|
||||||
add_child(pNew);
|
|
||||||
|
|
||||||
pNew->AddRoom(pRoomTo->get_path());
|
|
||||||
pNew->CopyReversedGeometry(*pPortalFrom);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void LRoom::_bind_methods() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
51
lroom.h
51
lroom.h
@ -47,56 +47,55 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class LRoom : public Spatial {
|
|
||||||
GDCLASS(LRoom, Spatial);
|
|
||||||
|
|
||||||
|
class LRoom
|
||||||
|
{
|
||||||
friend class LPortal;
|
friend class LPortal;
|
||||||
friend class LRoomManager;
|
friend class LRoomManager;
|
||||||
|
friend class LRoomConverter;
|
||||||
private:
|
private:
|
||||||
// a quick list of object IDs of child portals of this room
|
|
||||||
Vector<ObjectID> m_portal_IDs;
|
|
||||||
|
|
||||||
// godot vector for now .. can be lvector
|
// static objects
|
||||||
|
LVector<LSob> m_SOBs;
|
||||||
|
|
||||||
|
// dynamic objects
|
||||||
Vector<LDob> m_DOBs;
|
Vector<LDob> m_DOBs;
|
||||||
|
|
||||||
|
// portals are stored in the manager in a contiguous list
|
||||||
|
int m_iFirstPortal;
|
||||||
|
int m_iNumPortals;
|
||||||
|
|
||||||
// Just very rough, room centre for determining start rooms of dobs
|
// Just very rough, room centre for determining start rooms of dobs
|
||||||
Vector3 m_ptCentre;
|
Vector3 m_ptCentre;
|
||||||
|
AABB m_AABB; // world bound
|
||||||
|
|
||||||
// in the Room Manager, NOT the godot object ID
|
// ID in the Room Manager, NOT the godot object ID
|
||||||
int m_LocalRoomID;
|
int m_RoomID;
|
||||||
|
|
||||||
|
ObjectID m_GodotID;
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
||||||
|
String m_szName;
|
||||||
|
|
||||||
|
public:
|
||||||
|
const String &get_name() const {return m_szName;}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
|
||||||
|
|
||||||
// initial setup, allows importing portals as meshes from modelling program,
|
|
||||||
// which will be auto converted to LPortals with this method
|
|
||||||
void DetectPortalMeshes();
|
|
||||||
// assuming that portals are a child of the room, detect these and make them 2 way
|
|
||||||
void MakePortalsTwoWay();
|
|
||||||
void MakePortalQuickList();
|
|
||||||
|
|
||||||
// main function
|
// main function
|
||||||
void DetermineVisibility_Recursive(LRoomManager &manager, int depth, const LCamera &cam, const LVector<Plane> &planes, Lawn::LBitField_Dynamic &BF_visible, ObjectID portalID_from = 0);
|
void DetermineVisibility_Recursive(LRoomManager &manager, int depth, const LCamera &cam, const LVector<Plane> &planes, int portalID_from = -1);
|
||||||
|
|
||||||
// dynamic objects
|
|
||||||
// bool UpdateDynamicObject(Node * pDynObj);
|
|
||||||
|
|
||||||
void AddDOB(Spatial * pDOB);
|
void AddDOB(Spatial * pDOB);
|
||||||
bool RemoveDOB(Node * pDOB);
|
bool RemoveDOB(Node * pDOB);
|
||||||
LRoom * UpdateDOB(Spatial * pDOB);
|
LRoom * UpdateDOB(LRoomManager &manager, Spatial * pDOB);
|
||||||
// specific
|
|
||||||
public:
|
public:
|
||||||
LRoom();
|
LRoom();
|
||||||
|
Spatial * GetGodotRoom() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
// void SetupPortal(LPortal * pPortal);
|
|
||||||
void MakeOppositePortal(LPortal * pPortalFrom, LRoom * pRoomTo);
|
|
||||||
void DetectedPortalMesh(MeshInstance * pMeshInstance, String szLinkRoom);
|
|
||||||
static void print(String sz);
|
static void print(String sz);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
357
lroom_converter.cpp
Normal file
357
lroom_converter.cpp
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
// Copyright (c) 2019 Lawnjelly
|
||||||
|
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
#include "lroom_converter.h"
|
||||||
|
#include "lroom_manager.h"
|
||||||
|
#include "lportal.h"
|
||||||
|
#include "scene/3d/mesh_instance.h"
|
||||||
|
|
||||||
|
// save typing, I am lazy
|
||||||
|
#define LMAN m_pManager
|
||||||
|
|
||||||
|
void LRoomConverter::print(String sz)
|
||||||
|
{
|
||||||
|
// easy to turn on and off debugging
|
||||||
|
print_line(sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LRoomConverter::Convert(LRoomManager &manager)
|
||||||
|
{
|
||||||
|
// This just is simply used to set how much debugging output .. more during conversion, less during running
|
||||||
|
// except when requested by explicitly clearing this flag.
|
||||||
|
LPortal::m_bRunning = false;
|
||||||
|
print_line("running convert");
|
||||||
|
|
||||||
|
LMAN = &manager;
|
||||||
|
int count = CountRooms();
|
||||||
|
|
||||||
|
// make sure bitfield is right size for number of rooms
|
||||||
|
LMAN->m_BF_visible_rooms.Create(count);
|
||||||
|
|
||||||
|
|
||||||
|
LMAN->m_Rooms.clear(true);
|
||||||
|
LMAN->m_Rooms.resize(count);
|
||||||
|
|
||||||
|
m_TempRooms.clear(true);
|
||||||
|
m_TempRooms.resize(count);
|
||||||
|
|
||||||
|
|
||||||
|
Convert_Rooms();
|
||||||
|
Convert_Portals();
|
||||||
|
LPortal::m_bRunning = true;
|
||||||
|
|
||||||
|
// temp rooms no longer needed
|
||||||
|
m_TempRooms.clear(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LRoomConverter::Convert_Rooms()
|
||||||
|
{
|
||||||
|
print_line("Convert_Rooms");
|
||||||
|
|
||||||
|
// first find all room empties and convert to LRooms
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (int n=0; n<LMAN->get_child_count(); n++)
|
||||||
|
{
|
||||||
|
Node * pChild = LMAN->get_child(n);
|
||||||
|
|
||||||
|
if (!Node_IsRoom(pChild))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Spatial * pSpat = Object::cast_to<Spatial>(pChild);
|
||||||
|
assert (pSpat);
|
||||||
|
|
||||||
|
Convert_Room(pSpat, count++);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int LRoomConverter::FindRoom_ByName(String szName) const
|
||||||
|
{
|
||||||
|
for (int n=0; n<LMAN->m_Rooms.size(); n++)
|
||||||
|
{
|
||||||
|
if (LMAN->m_Rooms[n].m_szName == szName)
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LRoomConverter::Convert_Room(Spatial * pNode, int lroomID)
|
||||||
|
{
|
||||||
|
// get the room part of the name
|
||||||
|
String szFullName = pNode->get_name();
|
||||||
|
String szRoom = LPortal::FindNameAfter(pNode, "room_");
|
||||||
|
|
||||||
|
print_line("Convert_Room : " + szFullName);
|
||||||
|
|
||||||
|
// get a reference to the lroom we are writing to
|
||||||
|
LRoom &lroom = LMAN->m_Rooms[lroomID];
|
||||||
|
|
||||||
|
// store the godot room
|
||||||
|
lroom.m_GodotID = pNode->get_instance_id();
|
||||||
|
lroom.m_RoomID = lroomID;
|
||||||
|
|
||||||
|
// create a new LRoom to exchange the children over to, and delete the original empty
|
||||||
|
lroom.m_szName = szRoom;
|
||||||
|
|
||||||
|
// keep a running bounding volume as we go through the visual instances
|
||||||
|
// to determine the overall bound of the room
|
||||||
|
LAABB bb_room;
|
||||||
|
bb_room.SetToMaxOpposite();
|
||||||
|
|
||||||
|
int nChildren = pNode->get_child_count();
|
||||||
|
for (int n=0; n<nChildren; n++)
|
||||||
|
{
|
||||||
|
Node * pChild = pNode->get_child(n);
|
||||||
|
|
||||||
|
VisualInstance * pVI = Object::cast_to<VisualInstance>(pChild);
|
||||||
|
if (pVI)
|
||||||
|
{
|
||||||
|
print("\t\tFound VI : " + pVI->get_name());
|
||||||
|
|
||||||
|
|
||||||
|
// update bound to find centre of room roughly
|
||||||
|
AABB bb = pVI->get_transformed_aabb();
|
||||||
|
bb_room.ExpandToEnclose(bb);
|
||||||
|
|
||||||
|
// store some info about the static object for use at runtime
|
||||||
|
LSob sob;
|
||||||
|
sob.m_ID = pVI->get_instance_id();
|
||||||
|
sob.m_aabb = bb;
|
||||||
|
|
||||||
|
lroom.m_SOBs.push_back(sob);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// not visual instances NYI
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// store the lroom centre and bound
|
||||||
|
lroom.m_ptCentre = bb_room.FindCentre();
|
||||||
|
|
||||||
|
// bound (untested)
|
||||||
|
lroom.m_AABB.position = bb_room.m_ptMins;
|
||||||
|
lroom.m_AABB.size = bb_room.m_ptMaxs - bb_room.m_ptMins;
|
||||||
|
|
||||||
|
print_line("\t" + String(lroom.m_szName) + " centre " + lroom.m_ptCentre);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LRoomConverter::Convert_Portals()
|
||||||
|
{
|
||||||
|
for (int pass=0; pass<3; pass++)
|
||||||
|
{
|
||||||
|
print_line("Convert_Portals pass " + itos(pass));
|
||||||
|
|
||||||
|
for (int n=0; n<LMAN->m_Rooms.size(); n++)
|
||||||
|
{
|
||||||
|
LRoom &lroom = LMAN->m_Rooms[n];
|
||||||
|
LTempRoom &troom = m_TempRooms[n];
|
||||||
|
|
||||||
|
switch (pass)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
LRoom_DetectPortalMeshes(lroom, troom);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
LRoom_MakePortalsTwoWay(lroom, troom, n);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
LRoom_MakePortalFinalList(lroom, troom);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int LRoomConverter::CountRooms()
|
||||||
|
{
|
||||||
|
int nChildren = LMAN->get_child_count();
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (int n=0; n<nChildren; n++)
|
||||||
|
{
|
||||||
|
if (Node_IsRoom(LMAN->get_child(n)))
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// go through the nodes hanging off the room looking for those that are meshes to mark portal locations
|
||||||
|
void LRoomConverter::LRoom_DetectPortalMeshes(LRoom &lroom, LTempRoom &troom)
|
||||||
|
{
|
||||||
|
print("DetectPortalMeshes");
|
||||||
|
|
||||||
|
Spatial * pGRoom = lroom.GetGodotRoom();
|
||||||
|
assert (pGRoom);
|
||||||
|
|
||||||
|
for (int n=0; n<pGRoom->get_child_count(); n++)
|
||||||
|
{
|
||||||
|
Node * pChild = pGRoom->get_child(n);
|
||||||
|
|
||||||
|
MeshInstance * pMesh = Object::cast_to<MeshInstance>(pChild);
|
||||||
|
if (pMesh)
|
||||||
|
{
|
||||||
|
// name must start with 'portal_'
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// handles the slight faff involved in getting a new portal in the manager contiguous list of portals
|
||||||
|
LPortal * LRoomConverter::LRoom_RequestNewPortal(LRoom &lroom)
|
||||||
|
{
|
||||||
|
// is this the first portal?
|
||||||
|
if (lroom.m_iNumPortals == 0)
|
||||||
|
lroom.m_iFirstPortal = LMAN->m_Portals.size();
|
||||||
|
|
||||||
|
lroom.m_iNumPortals++;
|
||||||
|
|
||||||
|
return LMAN->m_Portals.request();
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert the list on each room to a single contiguous list in the manager
|
||||||
|
void LRoomConverter::LRoom_MakePortalFinalList(LRoom &lroom, LTempRoom &troom)
|
||||||
|
{
|
||||||
|
for (int n=0; n<troom.m_Portals.size(); n++)
|
||||||
|
{
|
||||||
|
LPortal &lport_final = *LRoom_RequestNewPortal(lroom);
|
||||||
|
lport_final = troom.m_Portals[n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// found a portal mesh! create a matching LPortal
|
||||||
|
void LRoomConverter::LRoom_DetectedPortalMesh(LRoom &lroom, LTempRoom &troom, MeshInstance * pMeshInstance, String szLinkRoom)
|
||||||
|
{
|
||||||
|
print("\tDetected PortalMesh");
|
||||||
|
|
||||||
|
// which room does this portal want to link to?
|
||||||
|
int iLinkRoom = FindRoom_ByName(szLinkRoom);
|
||||||
|
if (iLinkRoom == -1)
|
||||||
|
{
|
||||||
|
WARN_PRINTS("portal to room " + szLinkRoom + ", room not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// some godot jiggery pokery to get the mesh verts in local space
|
||||||
|
Ref<Mesh> rmesh = pMeshInstance->get_mesh();
|
||||||
|
Array arrays = rmesh->surface_get_arrays(0);
|
||||||
|
PoolVector<Vector3> p_vertices = arrays[VS::ARRAY_VERTEX];
|
||||||
|
|
||||||
|
// create a new LPortal to fill with this wonderful info
|
||||||
|
LPortal &lport = *troom.m_Portals.request();
|
||||||
|
lport.m_szName = szLinkRoom;
|
||||||
|
lport.m_iRoomNum = iLinkRoom;
|
||||||
|
|
||||||
|
// create the portal geometry
|
||||||
|
lport.CreateGeometry(p_vertices, pMeshInstance->get_global_transform());
|
||||||
|
|
||||||
|
// delete the original child, as it is no longer needed at runtime (except maybe for debugging .. NYI?)
|
||||||
|
// pMeshInstance->hide();
|
||||||
|
pMeshInstance->get_parent()->remove_child(pMeshInstance);
|
||||||
|
pMeshInstance->queue_delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This aims to make life easier for level designers. They only need to make a portal facing one way and LPortal
|
||||||
|
// will automatically create a mirror portal the other way.
|
||||||
|
void LRoomConverter::LRoom_MakePortalsTwoWay(LRoom &lroom, LTempRoom &troom, int iRoomNum)
|
||||||
|
{
|
||||||
|
for (int n=0; n<troom.m_Portals.size(); n++)
|
||||||
|
{
|
||||||
|
const LPortal &portal_orig = troom.m_Portals[n];
|
||||||
|
|
||||||
|
// get the temproom this portal is linking to
|
||||||
|
LTempRoom &nroom = m_TempRooms[portal_orig.m_iRoomNum];
|
||||||
|
|
||||||
|
// does a portal already exist back to the orig room?
|
||||||
|
// NOTE this doesn't cope with multiple portals between pairs of rooms yet.
|
||||||
|
bool bAlreadyLinked =false;
|
||||||
|
|
||||||
|
for (int p=0; p<nroom.m_Portals.size(); p++)
|
||||||
|
{
|
||||||
|
if (nroom.m_Portals[p].m_iRoomNum == n)
|
||||||
|
{
|
||||||
|
bAlreadyLinked = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bAlreadyLinked)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// needs a new reverse link if got to here
|
||||||
|
TRoom_MakeOppositePortal(portal_orig, iRoomNum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// There is a need for a mirror portal, let's make one!
|
||||||
|
void LRoomConverter::TRoom_MakeOppositePortal(const LPortal &port, int iRoomOrig)
|
||||||
|
{
|
||||||
|
LTempRoom &nroom = m_TempRooms[port.m_iRoomNum];
|
||||||
|
const LRoom &orig_lroom = LMAN->m_Rooms[iRoomOrig];
|
||||||
|
|
||||||
|
// the new portal should have the name of the room the original came from
|
||||||
|
LPortal &new_port = *nroom.m_Portals.request();
|
||||||
|
new_port.m_szName = orig_lroom.m_szName;
|
||||||
|
new_port.m_iRoomNum = iRoomOrig;
|
||||||
|
|
||||||
|
// the portal vertices should be the same but reversed (to flip the normal)
|
||||||
|
new_port.CopyReversedGeometry(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// helper
|
||||||
|
bool LRoomConverter::Node_IsRoom(Node * pNode) const
|
||||||
|
{
|
||||||
|
Spatial * pSpat = Object::cast_to<Spatial>(pNode);
|
||||||
|
if (!pSpat)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (LPortal::NameStartsWith(pSpat, "room_"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// keep the global namespace clean
|
||||||
|
#undef LMAN
|
88
lroom_converter.h
Normal file
88
lroom_converter.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "scene/3d/spatial.h"
|
||||||
|
#include "lvector.h"
|
||||||
|
#include "lportal.h"
|
||||||
|
|
||||||
|
class LRoomManager;
|
||||||
|
class LRoom;
|
||||||
|
class MeshInstance;
|
||||||
|
|
||||||
|
// simple min max aabb
|
||||||
|
class LAABB
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Vector3 m_ptMins;
|
||||||
|
Vector3 m_ptMaxs;
|
||||||
|
void SetToMaxOpposite()
|
||||||
|
{
|
||||||
|
float ma = FLT_MAX;
|
||||||
|
float mi = FLT_MIN;
|
||||||
|
m_ptMins = Vector3(ma, ma, ma);
|
||||||
|
m_ptMaxs = Vector3(mi, mi, mi);
|
||||||
|
}
|
||||||
|
void ExpandToEnclose(const AABB &bb)
|
||||||
|
{
|
||||||
|
if (bb.position.x < m_ptMins.x) m_ptMins.x = bb.position.x;
|
||||||
|
if (bb.position.y < m_ptMins.y) m_ptMins.y = bb.position.y;
|
||||||
|
if (bb.position.z < m_ptMins.z) m_ptMins.z = bb.position.z;
|
||||||
|
if (bb.position.x + bb.size.x > m_ptMaxs.x) m_ptMaxs.x = bb.position.x + bb.size.x;
|
||||||
|
if (bb.position.y + bb.size.y > m_ptMaxs.y) m_ptMaxs.y = bb.position.y + bb.size.y;
|
||||||
|
if (bb.position.z + bb.size.z > m_ptMaxs.z) m_ptMaxs.z = bb.position.z + bb.size.z;
|
||||||
|
}
|
||||||
|
Vector3 FindCentre() const
|
||||||
|
{
|
||||||
|
Vector3 pt;
|
||||||
|
pt.x = (m_ptMaxs.x - m_ptMins.x) * 0.5f;
|
||||||
|
pt.y = (m_ptMaxs.y - m_ptMins.y) * 0.5f;
|
||||||
|
pt.z = (m_ptMaxs.z - m_ptMins.z) * 0.5f;
|
||||||
|
pt += m_ptMins;
|
||||||
|
return pt;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LRoomConverter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// temp rooms are used as an intermediate during conversion, because we need to convert the original portals
|
||||||
|
// and the mirror portals from 2 bits of code, and we want to end up with a final contiguous list of portals
|
||||||
|
// for efficient rendering.
|
||||||
|
class LTempRoom
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LVector<LPortal> m_Portals;
|
||||||
|
};
|
||||||
|
|
||||||
|
// this function calls everything else in the converter
|
||||||
|
void Convert(LRoomManager &manager);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int CountRooms();
|
||||||
|
|
||||||
|
void Convert_Rooms();
|
||||||
|
bool Convert_Room(Spatial * pNode, int lroomID);
|
||||||
|
void Convert_Portals();
|
||||||
|
|
||||||
|
|
||||||
|
void LRoom_DetectPortalMeshes(LRoom &lroom, LTempRoom &troom);
|
||||||
|
void LRoom_MakePortalsTwoWay(LRoom &lroom, LTempRoom &troom, int iRoomNum);
|
||||||
|
void LRoom_MakePortalFinalList(LRoom &lroom, LTempRoom &troom);
|
||||||
|
void LRoom_DetectedPortalMesh(LRoom &lroom, LTempRoom &troom, MeshInstance * pMeshInstance, String szLinkRoom);
|
||||||
|
LPortal * LRoom_RequestNewPortal(LRoom &lroom);
|
||||||
|
|
||||||
|
void TRoom_MakeOppositePortal(const LPortal &port, int iRoomOrig);
|
||||||
|
|
||||||
|
|
||||||
|
// helper
|
||||||
|
bool Node_IsRoom(Node * pNode) const;
|
||||||
|
int FindRoom_ByName(String szName) const;
|
||||||
|
|
||||||
|
|
||||||
|
LRoomManager * m_pManager;
|
||||||
|
LVector<LTempRoom> m_TempRooms;
|
||||||
|
|
||||||
|
static void print(String sz);
|
||||||
|
|
||||||
|
};
|
@ -19,15 +19,13 @@
|
|||||||
// SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#include "lroom_manager.h"
|
#include "lroom_manager.h"
|
||||||
#include "lportal.h"
|
|
||||||
#include "lroom.h"
|
|
||||||
#include "core/engine.h"
|
#include "core/engine.h"
|
||||||
#include "scene/3d/camera.h"
|
#include "scene/3d/camera.h"
|
||||||
#include "scene/3d/mesh_instance.h"
|
#include "scene/3d/mesh_instance.h"
|
||||||
|
#include "lroom_converter.h"
|
||||||
|
|
||||||
LRoomManager::LRoomManager()
|
LRoomManager::LRoomManager()
|
||||||
{
|
{
|
||||||
// m_room_curr = 0;
|
|
||||||
m_cameraID = 0;
|
m_cameraID = 0;
|
||||||
m_uiFrameCounter = 0;
|
m_uiFrameCounter = 0;
|
||||||
}
|
}
|
||||||
@ -38,14 +36,11 @@ int LRoomManager::FindClosestRoom(const Vector3 &pt) const
|
|||||||
int closest = -1;
|
int closest = -1;
|
||||||
float closest_dist = FLT_MAX;
|
float closest_dist = FLT_MAX;
|
||||||
|
|
||||||
for (int n=0; n<m_room_IDs.size(); n++)
|
for (int n=0; n<m_Rooms.size(); n++)
|
||||||
{
|
{
|
||||||
LRoom * pRoom = GetRoomNum(n);
|
const LRoom &lroom = m_Rooms[n];
|
||||||
if (!pRoom)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
float d = pt.distance_squared_to(pRoom->m_ptCentre);
|
float d = pt.distance_squared_to(lroom.m_ptCentre);
|
||||||
// print_line("\troom " + itos(n) + " dist " + String(Variant(d)));
|
|
||||||
|
|
||||||
if (d < closest_dist)
|
if (d < closest_dist)
|
||||||
{
|
{
|
||||||
@ -58,32 +53,30 @@ int LRoomManager::FindClosestRoom(const Vector3 &pt) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LRoom * LRoomManager::GetRoomNum(int i) const
|
const LRoom * LRoomManager::GetRoom(int i) const
|
||||||
{
|
{
|
||||||
assert (i < m_room_IDs.size());
|
if ((unsigned int) i >= m_Rooms.size())
|
||||||
Object *pObj = ObjectDB::get_instance(m_room_IDs[i]);
|
{
|
||||||
if (!pObj)
|
WARN_PRINT_ONCE("LRoomManager::GetRoom out of range");
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
LRoom * pRoom = Object::cast_to<LRoom>(pObj);
|
return &m_Rooms[i];
|
||||||
if (!pRoom)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return pRoom;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int LRoomManager::GetRoomNumFromLRoom(LRoom * pRoom) const
|
LRoom * LRoomManager::GetRoom(int i)
|
||||||
{
|
{
|
||||||
// slow .. use metadata for this
|
if ((unsigned int) i >= m_Rooms.size())
|
||||||
int search_id = pRoom->get_instance_id();
|
|
||||||
|
|
||||||
for (int n=0; n<m_room_IDs.size(); n++)
|
|
||||||
{
|
{
|
||||||
if (m_room_IDs[n] == search_id)
|
WARN_PRINT_ONCE("LRoomManager::GetRoom out of range");
|
||||||
return n;
|
return 0;
|
||||||
}
|
}
|
||||||
|
return &m_Rooms[i];
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
|
||||||
|
LRoom &LRoomManager::Portal_GetLinkedRoom(const LPortal &port)
|
||||||
|
{
|
||||||
|
return m_Rooms[port.m_iRoomNum];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -104,7 +97,7 @@ int LRoomManager::Obj_GetRoomNum(Node * pNode) const
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRoom * LRoomManager::GetRoomFromDOB(Node * pNode) const
|
LRoom * LRoomManager::GetRoomFromDOB(Node * pNode)
|
||||||
{
|
{
|
||||||
int iRoom = Obj_GetRoomNum(pNode);
|
int iRoom = Obj_GetRoomNum(pNode);
|
||||||
if (iRoom == -1)
|
if (iRoom == -1)
|
||||||
@ -113,7 +106,7 @@ LRoom * LRoomManager::GetRoomFromDOB(Node * pNode) const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRoom * pRoom = GetRoomNum(iRoom);
|
LRoom * pRoom = GetRoom(iRoom);
|
||||||
if (pRoom == 0)
|
if (pRoom == 0)
|
||||||
{
|
{
|
||||||
WARN_PRINT_ONCE("LRoomManager::GetRoomFromDOB : pRoom is NULL");
|
WARN_PRINT_ONCE("LRoomManager::GetRoomFromDOB : pRoom is NULL");
|
||||||
@ -138,7 +131,7 @@ void LRoomManager::register_dob(Node * pDOB)
|
|||||||
if (iRoomNum == -1)
|
if (iRoomNum == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LRoom * pRoom = GetRoomNum(iRoomNum);
|
LRoom * pRoom = GetRoom(iRoomNum);
|
||||||
if (!pRoom)
|
if (!pRoom)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -163,12 +156,12 @@ bool LRoomManager::update_dob(Node * pDOB)
|
|||||||
// is it the camera?
|
// is it the camera?
|
||||||
//bool bCamera = pDOB->get_instance_id() == m_cameraID;
|
//bool bCamera = pDOB->get_instance_id() == m_cameraID;
|
||||||
|
|
||||||
LRoom * pNewRoom = pRoom->UpdateDOB(pSpat);
|
LRoom * pNewRoom = pRoom->UpdateDOB(*this, pSpat);
|
||||||
|
|
||||||
if (pNewRoom)
|
if (pNewRoom)
|
||||||
{
|
{
|
||||||
// remove from the list in old room and add to list in new room, and change the metadata
|
// remove from the list in old room and add to list in new room, and change the metadata
|
||||||
int iRoomNum = GetRoomNumFromLRoom(pNewRoom);
|
int iRoomNum = pNewRoom->m_RoomID;
|
||||||
|
|
||||||
pRoom->RemoveDOB(pDOB);
|
pRoom->RemoveDOB(pDOB);
|
||||||
pNewRoom->AddDOB(pSpat);
|
pNewRoom->AddDOB(pSpat);
|
||||||
@ -194,34 +187,6 @@ void LRoomManager::unregister_dob(Node * pDOB)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
bool LRoomManager::update_object(Node * pObj)
|
|
||||||
{
|
|
||||||
// find the room the object is attached to
|
|
||||||
Node * pParent = pObj->get_parent();
|
|
||||||
LRoom * pRoom = Object::cast_to<LRoom>(pParent);
|
|
||||||
if (!pRoom)
|
|
||||||
{
|
|
||||||
WARN_PRINT_ONCE("LRoomManager::update_object : object parent is not an LRoom");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bChanged = pRoom->UpdateDynamicObject(pObj);
|
|
||||||
|
|
||||||
// special .. for camera keep the camera room ID up to date
|
|
||||||
// could alternatively just use the parent of the camera?
|
|
||||||
// if (bChanged)
|
|
||||||
// {
|
|
||||||
// if (pObj->get_instance_id() == m_cameraID)
|
|
||||||
// {
|
|
||||||
// m_room_curr = pObj->get_parent()->get_instance_id();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
return bChanged;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
void LRoomManager::set_camera(Node * pCam)
|
void LRoomManager::set_camera(Node * pCam)
|
||||||
{
|
{
|
||||||
m_cameraID = 0;
|
m_cameraID = 0;
|
||||||
@ -245,192 +210,10 @@ void LRoomManager::set_camera(Node * pCam)
|
|||||||
// convert empties and meshes to rooms and portals
|
// convert empties and meshes to rooms and portals
|
||||||
void LRoomManager::convert()
|
void LRoomManager::convert()
|
||||||
{
|
{
|
||||||
LPortal::m_bRunning = false;
|
LRoomConverter conv;
|
||||||
print_line("running convert");
|
conv.Convert(*this);
|
||||||
|
|
||||||
Convert_Rooms();
|
|
||||||
Convert_Portals();
|
|
||||||
Find_Rooms();
|
|
||||||
LPortal::m_bRunning = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LRoomManager::Find_Rooms()
|
|
||||||
{
|
|
||||||
print_line ("Find_Rooms");
|
|
||||||
m_room_IDs.clear();
|
|
||||||
|
|
||||||
// first find all room empties and convert to LRooms
|
|
||||||
for (int n=0; n<get_child_count(); n++)
|
|
||||||
{
|
|
||||||
Node * pChild = get_child(n);
|
|
||||||
|
|
||||||
// don't want to handle already converted rooms
|
|
||||||
LRoom * pRoom = Object::cast_to<LRoom>(pChild);
|
|
||||||
if (pRoom)
|
|
||||||
{
|
|
||||||
pRoom->m_LocalRoomID = m_room_IDs.size();
|
|
||||||
m_room_IDs.push_back(pRoom->get_instance_id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
m_room_curr = 0;
|
|
||||||
|
|
||||||
// just set current room to first room
|
|
||||||
if (m_room_IDs.size())
|
|
||||||
{
|
|
||||||
m_room_curr = m_room_IDs[0];
|
|
||||||
print_line("first room ID is " + itos(m_room_curr));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// make sure bitfield is right size for number of rooms
|
|
||||||
m_BF_visible_rooms.Create(m_room_IDs.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void LRoomManager::Convert_Rooms()
|
|
||||||
{
|
|
||||||
print_line("Convert_Rooms");
|
|
||||||
|
|
||||||
bool bConvertedOne = true;
|
|
||||||
|
|
||||||
// instead of recursive routine
|
|
||||||
while (bConvertedOne)
|
|
||||||
{
|
|
||||||
bConvertedOne = false;
|
|
||||||
|
|
||||||
// first find all room empties and convert to LRooms
|
|
||||||
for (int n=0; n<get_child_count(); n++)
|
|
||||||
{
|
|
||||||
Node * pChild = get_child(n);
|
|
||||||
|
|
||||||
// don't want to handle already converted rooms
|
|
||||||
LRoom * pRoom = Object::cast_to<LRoom>(pChild);
|
|
||||||
if (pRoom)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Spatial * pSpatialChild = Object::cast_to<Spatial>(pChild);
|
|
||||||
if (!pSpatialChild)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (LPortal::NameStartsWith(pSpatialChild, "room_"))
|
|
||||||
{
|
|
||||||
if (Convert_Room(pSpatialChild))
|
|
||||||
bConvertedOne = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bConvertedOne)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void LRoomManager::Convert_Portals()
|
|
||||||
{
|
|
||||||
for (int pass=0; pass<3; pass++)
|
|
||||||
{
|
|
||||||
print_line("Convert_Portals pass " + itos(pass));
|
|
||||||
|
|
||||||
// first find all room empties and convert to LRooms
|
|
||||||
for (int n=0; n<get_child_count(); n++)
|
|
||||||
{
|
|
||||||
Node * pChild = get_child(n);
|
|
||||||
|
|
||||||
// don't want to handle already converted rooms
|
|
||||||
LRoom * pRoom = Object::cast_to<LRoom>(pChild);
|
|
||||||
if (pRoom)
|
|
||||||
{
|
|
||||||
switch (pass)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
pRoom->DetectPortalMeshes();
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
pRoom->MakePortalsTwoWay();
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
pRoom->MakePortalQuickList();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool LRoomManager::Convert_Room(Spatial * pNode)
|
|
||||||
{
|
|
||||||
// get the room part of the name
|
|
||||||
String szFullName = pNode->get_name();
|
|
||||||
String szRoom = LPortal::FindNameAfter(pNode, "room_");
|
|
||||||
|
|
||||||
print_line("Convert_Room : " + szFullName);
|
|
||||||
|
|
||||||
// create a new LRoom to exchange the children over to, and delete the original empty
|
|
||||||
LRoom * pNew = memnew(LRoom);
|
|
||||||
pNew->set_name(szRoom);
|
|
||||||
add_child(pNew);
|
|
||||||
|
|
||||||
// make the transform of the L room match the original spatial
|
|
||||||
pNew->set_transform(pNode->get_transform());
|
|
||||||
|
|
||||||
// New .. room is at origin, all the child nodes are now transformed
|
|
||||||
// so everything is in world space ... makes dynamic objects changing rooms easier
|
|
||||||
//Transform tr_orig = pNode->get_transform();
|
|
||||||
|
|
||||||
int nChildren = pNode->get_child_count();
|
|
||||||
|
|
||||||
LAABB bb_room;
|
|
||||||
bb_room.SetToMaxOpposite();
|
|
||||||
|
|
||||||
for (int n=0; n<nChildren; n++)
|
|
||||||
{
|
|
||||||
// reverse count
|
|
||||||
int c = nChildren - n - 1;
|
|
||||||
|
|
||||||
Node * pChild = pNode->get_child(c);
|
|
||||||
|
|
||||||
// change the transform of the child to take away the room transform
|
|
||||||
// Spatial * pSChild = Object::cast_to<Spatial>(pChild);
|
|
||||||
// Transform tr_world;
|
|
||||||
// if (pSChild)
|
|
||||||
// {
|
|
||||||
// tr_world = pSChild->get_global_transform();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// update bound to find centre of room roughly
|
|
||||||
VisualInstance * pVI = Object::cast_to<VisualInstance>(pChild);
|
|
||||||
if (pVI)
|
|
||||||
{
|
|
||||||
AABB bb = pVI->get_transformed_aabb();
|
|
||||||
bb_room.ExpandToEnclose(bb);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pNode->remove_child(pChild);
|
|
||||||
|
|
||||||
// add the child to the new node
|
|
||||||
pNew->add_child(pChild);
|
|
||||||
|
|
||||||
|
|
||||||
// if (pSChild)
|
|
||||||
// {
|
|
||||||
// pSChild->set_transform(tr_world);
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pNew->m_ptCentre = bb_room.FindCentre();
|
|
||||||
print_line(String(pNew->get_name()) + " centre " + pNew->m_ptCentre);
|
|
||||||
|
|
||||||
// all moved .. now finally delete the empty
|
|
||||||
remove_child(pNode);
|
|
||||||
pNode->queue_delete();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LRoomManager::FrameUpdate()
|
void LRoomManager::FrameUpdate()
|
||||||
{
|
{
|
||||||
@ -440,6 +223,7 @@ void LRoomManager::FrameUpdate()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we keep a frame counter to prevent visiting things multiple times on the same frame in recursive functions
|
||||||
m_uiFrameCounter++;
|
m_uiFrameCounter++;
|
||||||
|
|
||||||
// get the camera desired and make into lcamera
|
// get the camera desired and make into lcamera
|
||||||
@ -450,42 +234,37 @@ void LRoomManager::FrameUpdate()
|
|||||||
pCamera = Object::cast_to<Camera>(pObj);
|
pCamera = Object::cast_to<Camera>(pObj);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// camera not set
|
// camera not set .. do nothing
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// camera not a camera??
|
// camera not a camera?? shouldn't happen but we'll check
|
||||||
if (!pCamera)
|
if (!pCamera)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// if not started
|
// Which room is the camera currently in?
|
||||||
// if (!m_room_curr)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
// determine visibility
|
|
||||||
// Object *pObj = ObjectDB::get_instance(m_room_curr);
|
|
||||||
LRoom * pRoom = GetRoomFromDOB(pCamera);
|
LRoom * pRoom = GetRoomFromDOB(pCamera);
|
||||||
// Node * pObj = pCamera->get_parent();
|
|
||||||
|
|
||||||
// if (!pObj)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
// LRoom * pRoom = Object::cast_to<LRoom>(pObj);
|
|
||||||
if (!pRoom)
|
if (!pRoom)
|
||||||
{
|
{
|
||||||
WARN_PRINT_ONCE("LRoomManager::FrameUpdate : curr room is not an LRoom");
|
WARN_PRINT_ONCE("LRoomManager::FrameUpdate : Camera is not in an LRoom");
|
||||||
//print_line("LRoomManager::FrameUpdate : curr room is not an LRoom");
|
|
||||||
// m_room_curr = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// as we hit visible rooms we will mark them in a bitset, so we can hide any rooms
|
||||||
|
// that are showing that haven't been hit this frame
|
||||||
m_BF_visible_rooms.Blank();
|
m_BF_visible_rooms.Blank();
|
||||||
|
|
||||||
|
// lcamera contains the info needed for culling
|
||||||
LCamera cam;
|
LCamera cam;
|
||||||
cam.m_ptPos = Vector3(0, 0, 0);
|
cam.m_ptPos = Vector3(0, 0, 0);
|
||||||
cam.m_ptDir = Vector3 (-1, 0, 0);
|
cam.m_ptDir = Vector3 (-1, 0, 0);
|
||||||
|
|
||||||
// reset the pool for another frame
|
// reset the planes pool for another frame
|
||||||
m_Pool.Reset();
|
m_Pool.Reset();
|
||||||
|
|
||||||
|
// the first set of planes are allocated and filled with the view frustum planes
|
||||||
|
// Note that the visual server doesn't actually need to do view frustum culling as a result...
|
||||||
|
// (but is still doing it for now)
|
||||||
unsigned int pool_member = m_Pool.Request();
|
unsigned int pool_member = m_Pool.Request();
|
||||||
assert (pool_member != -1);
|
assert (pool_member != -1);
|
||||||
|
|
||||||
@ -494,39 +273,29 @@ void LRoomManager::FrameUpdate()
|
|||||||
|
|
||||||
// get the camera desired and make into lcamera
|
// get the camera desired and make into lcamera
|
||||||
assert (pCamera);
|
assert (pCamera);
|
||||||
// if (pCamera)
|
Transform tr = pCamera->get_global_transform();
|
||||||
{
|
cam.m_ptPos = tr.origin;
|
||||||
Transform tr = pCamera->get_global_transform();
|
cam.m_ptDir = tr.basis.get_row(2); // or possibly get_axis .. z is what we want
|
||||||
cam.m_ptPos = tr.origin;
|
|
||||||
cam.m_ptDir = tr.basis.get_row(2); // or possibly get_axis .. z is what we want
|
|
||||||
|
|
||||||
planes.copy_from(pCamera->get_frustum());
|
// luckily godot already has a function to return a list of the camera clipping planes
|
||||||
}
|
planes.copy_from(pCamera->get_frustum());
|
||||||
|
|
||||||
pRoom->DetermineVisibility_Recursive(*this, 0, cam, planes, m_BF_visible_rooms);
|
|
||||||
|
|
||||||
|
// the whole visibility algorithm is recursive, spreading out from the camera room,
|
||||||
|
// rendering through any portals in view into other rooms, etc etc
|
||||||
|
pRoom->DetermineVisibility_Recursive(*this, 0, cam, planes);
|
||||||
|
|
||||||
// finally hide all the rooms that are currently visible but not in the visible bitfield as having been hit
|
// finally hide all the rooms that are currently visible but not in the visible bitfield as having been hit
|
||||||
// NOTE this could be more efficient
|
// NOTE this will be done more efficiently, but is okay to start with
|
||||||
for (int n=0; n<m_room_IDs.size(); n++)
|
for (int n=0; n<m_Rooms.size(); n++)
|
||||||
{
|
{
|
||||||
Object *pObj = ObjectDB::get_instance(m_room_IDs[n]);
|
if (!m_BF_visible_rooms.GetBit(n))
|
||||||
|
|
||||||
LRoom * pRoom = Object::cast_to<LRoom>(pObj);
|
|
||||||
if (pRoom)
|
|
||||||
{
|
{
|
||||||
if (!m_BF_visible_rooms.GetBit(n))
|
m_Rooms[n].GetGodotRoom()->hide();
|
||||||
{
|
|
||||||
pRoom->hide();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// when running, emit less debugging output so as not to choke the IDE
|
||||||
LPortal::m_bRunning = true;
|
LPortal::m_bRunning = true;
|
||||||
|
|
||||||
|
|
||||||
// only do once for now
|
|
||||||
// m_room_curr = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -534,46 +303,30 @@ void LRoomManager::_notification(int p_what) {
|
|||||||
|
|
||||||
switch (p_what) {
|
switch (p_what) {
|
||||||
case NOTIFICATION_ENTER_TREE: {
|
case NOTIFICATION_ENTER_TREE: {
|
||||||
// bool bVisible = is_visible_in_tree();
|
// turn on process, unless we are in the editor
|
||||||
// ChangeFlags(SF_INVISIBLE, bVisible == false);
|
|
||||||
// SetProcessing();
|
|
||||||
if (!Engine::get_singleton()->is_editor_hint())
|
if (!Engine::get_singleton()->is_editor_hint())
|
||||||
set_process_internal(true);
|
set_process_internal(true);
|
||||||
else
|
else
|
||||||
set_process_internal(false);
|
set_process_internal(false);
|
||||||
|
|
||||||
// // we can't translate string name of Target to a node until we are in the tree
|
|
||||||
// ResolveTargetPath();
|
|
||||||
} break;
|
} break;
|
||||||
// case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
|
|
||||||
// FixedUpdate();
|
|
||||||
// } break;
|
|
||||||
case NOTIFICATION_INTERNAL_PROCESS: {
|
case NOTIFICATION_INTERNAL_PROCESS: {
|
||||||
FrameUpdate();
|
FrameUpdate();
|
||||||
} break;
|
} break;
|
||||||
// case NOTIFICATION_VISIBILITY_CHANGED: {
|
|
||||||
// bool bVisible = is_visible_in_tree();
|
|
||||||
// ChangeFlags(SF_INVISIBLE, bVisible == false);
|
|
||||||
// SetProcessing();
|
|
||||||
//// if (bVisible)
|
|
||||||
//// print_line("now visible");
|
|
||||||
//// else
|
|
||||||
//// print_line("now hidden");
|
|
||||||
// } break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LRoomManager::_bind_methods()
|
void LRoomManager::_bind_methods()
|
||||||
{
|
{
|
||||||
|
// main functions
|
||||||
ClassDB::bind_method(D_METHOD("rooms_convert"), &LRoomManager::convert);
|
ClassDB::bind_method(D_METHOD("rooms_convert"), &LRoomManager::convert);
|
||||||
ClassDB::bind_method(D_METHOD("rooms_set_camera"), &LRoomManager::set_camera);
|
ClassDB::bind_method(D_METHOD("rooms_set_camera"), &LRoomManager::set_camera);
|
||||||
// ClassDB::bind_method(D_METHOD("update_object"), &LRoomManager::update_object);
|
|
||||||
|
|
||||||
|
|
||||||
|
// functions to add dynamic objects to the culling system
|
||||||
|
// Note that these should not be placed directly in rooms, the system will 'soft link' to them
|
||||||
|
// so they can be held, e.g. in pools elsewhere in the scene graph
|
||||||
ClassDB::bind_method(D_METHOD("dob_register"), &LRoomManager::register_dob);
|
ClassDB::bind_method(D_METHOD("dob_register"), &LRoomManager::register_dob);
|
||||||
ClassDB::bind_method(D_METHOD("dob_unregister"), &LRoomManager::unregister_dob);
|
ClassDB::bind_method(D_METHOD("dob_unregister"), &LRoomManager::unregister_dob);
|
||||||
ClassDB::bind_method(D_METHOD("dob_update"), &LRoomManager::update_dob);
|
ClassDB::bind_method(D_METHOD("dob_update"), &LRoomManager::update_dob);
|
||||||
ClassDB::bind_method(D_METHOD("dob_teleport"), &LRoomManager::teleport_dob);
|
ClassDB::bind_method(D_METHOD("dob_teleport"), &LRoomManager::teleport_dob);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,58 +30,26 @@
|
|||||||
#include "lbitfield_dynamic.h"
|
#include "lbitfield_dynamic.h"
|
||||||
#include "lplanes_pool.h"
|
#include "lplanes_pool.h"
|
||||||
|
|
||||||
|
#include "lroom.h"
|
||||||
|
#include "lportal.h"
|
||||||
|
|
||||||
class LRoom;
|
|
||||||
|
|
||||||
// simple min max aabb
|
|
||||||
class LAABB
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Vector3 m_ptMins;
|
|
||||||
Vector3 m_ptMaxs;
|
|
||||||
void SetToMaxOpposite()
|
|
||||||
{
|
|
||||||
float ma = FLT_MAX;
|
|
||||||
float mi = FLT_MIN;
|
|
||||||
m_ptMins = Vector3(ma, ma, ma);
|
|
||||||
m_ptMaxs = Vector3(mi, mi, mi);
|
|
||||||
}
|
|
||||||
void ExpandToEnclose(const AABB &bb)
|
|
||||||
{
|
|
||||||
if (bb.position.x < m_ptMins.x) m_ptMins.x = bb.position.x;
|
|
||||||
if (bb.position.y < m_ptMins.y) m_ptMins.y = bb.position.y;
|
|
||||||
if (bb.position.z < m_ptMins.z) m_ptMins.z = bb.position.z;
|
|
||||||
if (bb.position.x + bb.size.x > m_ptMaxs.x) m_ptMaxs.x = bb.position.x + bb.size.x;
|
|
||||||
if (bb.position.y + bb.size.y > m_ptMaxs.y) m_ptMaxs.y = bb.position.y + bb.size.y;
|
|
||||||
if (bb.position.z + bb.size.z > m_ptMaxs.z) m_ptMaxs.z = bb.position.z + bb.size.z;
|
|
||||||
}
|
|
||||||
Vector3 FindCentre() const
|
|
||||||
{
|
|
||||||
Vector3 pt;
|
|
||||||
pt.x = (m_ptMaxs.x - m_ptMins.x) * 0.5f;
|
|
||||||
pt.y = (m_ptMaxs.y - m_ptMins.y) * 0.5f;
|
|
||||||
pt.z = (m_ptMaxs.z - m_ptMins.z) * 0.5f;
|
|
||||||
pt += m_ptMins;
|
|
||||||
return pt;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class LRoomManager : public Spatial {
|
class LRoomManager : public Spatial {
|
||||||
GDCLASS(LRoomManager, Spatial);
|
GDCLASS(LRoomManager, Spatial);
|
||||||
|
|
||||||
friend class LRoom;
|
friend class LRoom;
|
||||||
|
friend class LRoomConverter;
|
||||||
|
|
||||||
// a quick list of object IDs of child rooms
|
|
||||||
Vector<ObjectID> m_room_IDs;
|
|
||||||
|
|
||||||
// ObjectID m_room_curr;
|
// godot ID of the camera (which should be registered as a DOB to allow moving between rooms)
|
||||||
ObjectID m_cameraID;
|
ObjectID m_cameraID;
|
||||||
|
|
||||||
// keep track of which rooms are visible, so we can hide ones that aren't hit that were previously on
|
// keep track of which rooms are visible, so we can hide ones that aren't hit that were previously on
|
||||||
Lawn::LBitField_Dynamic m_BF_visible_rooms;
|
Lawn::LBitField_Dynamic m_BF_visible_rooms;
|
||||||
Vector<int> m_VisibleRoomList[2];
|
// Vector<int> m_VisibleRoomList[2];
|
||||||
int m_CurrentVisibleRoomList;
|
// int m_CurrentVisibleRoomList;
|
||||||
|
|
||||||
// keep a frame counter, to mark when objects have been hit by the visiblity algorithm
|
// keep a frame counter, to mark when objects have been hit by the visiblity algorithm
|
||||||
// already to prevent multiple hits on rooms and objects
|
// already to prevent multiple hits on rooms and objects
|
||||||
@ -97,7 +65,10 @@ public:
|
|||||||
// normally this will be your main camera, but you can choose another for debugging
|
// normally this will be your main camera, but you can choose another for debugging
|
||||||
void set_camera(Node * pCam);
|
void set_camera(Node * pCam);
|
||||||
|
|
||||||
// updating dynamic objects in case they move out of their current room
|
// Dynamic objects .. cameras, players, boxes etc
|
||||||
|
// These are defined by their ability to move from room to room.
|
||||||
|
// You can still move static objects within the same room (e.g. elevators, moving platforms)
|
||||||
|
// as these don't require checks for changing rooms.
|
||||||
void register_dob(Node * pDOB);
|
void register_dob(Node * pDOB);
|
||||||
void unregister_dob(Node * pDOB);
|
void unregister_dob(Node * pDOB);
|
||||||
bool update_dob(Node * pDOB);
|
bool update_dob(Node * pDOB);
|
||||||
@ -108,25 +79,32 @@ protected:
|
|||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
|
|
||||||
|
// The recursive visibility function needs to allocate loads of planes.
|
||||||
|
// We use a pool for this instead of allocating on the fly.
|
||||||
LPlanesPool m_Pool;
|
LPlanesPool m_Pool;
|
||||||
private:
|
private:
|
||||||
// one time conversion and setup
|
|
||||||
void Convert_Rooms();
|
|
||||||
bool Convert_Room(Spatial * pNode);
|
|
||||||
void Convert_Portals();
|
|
||||||
void Find_Rooms();
|
|
||||||
|
|
||||||
// helper funcs
|
// helper funcs
|
||||||
LRoom * GetRoomNum(int i) const;
|
const LRoom * GetRoom(int i) const;
|
||||||
LRoom * GetRoomFromDOB(Node * pNode) const;
|
LRoom * GetRoom(int i);
|
||||||
int GetRoomNumFromLRoom(LRoom * pRoom) const;
|
|
||||||
|
LRoom * GetRoomFromDOB(Node * pNode);
|
||||||
int FindClosestRoom(const Vector3 &pt) const;
|
int FindClosestRoom(const Vector3 &pt) const;
|
||||||
|
|
||||||
|
// for DOBs, we need some way of storing the room ID on them, so we use metadata (currently)
|
||||||
|
// this is pretty gross but hey ho
|
||||||
int Obj_GetRoomNum(Node * pNode) const;
|
int Obj_GetRoomNum(Node * pNode) const;
|
||||||
void Obj_SetRoomNum(Node * pNode, int num);
|
void Obj_SetRoomNum(Node * pNode, int num);
|
||||||
|
|
||||||
|
// this is where we do all the culling
|
||||||
void FrameUpdate();
|
void FrameUpdate();
|
||||||
|
|
||||||
|
// find which room is linked by a portal
|
||||||
|
LRoom &Portal_GetLinkedRoom(const LPortal &port);
|
||||||
|
|
||||||
|
// lists of rooms and portals, contiguous list so cache friendly
|
||||||
|
LVector<LRoom> m_Rooms;
|
||||||
|
LVector<LPortal> m_Portals;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
68
lvector.h
68
lvector.h
@ -1,8 +1,30 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// just a light wrapper around the Godot vector until we get the allocation issues sorted
|
// Copyright (c) 2019 Lawnjelly
|
||||||
|
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
// just a light wrapper around the a vector until we get the Godot vector allocation issues sorted
|
||||||
#include "core/vector.h"
|
#include "core/vector.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
template <class T> class LVector
|
template <class T> class LVector
|
||||||
{
|
{
|
||||||
@ -14,6 +36,7 @@ public:
|
|||||||
assert (ui < m_iSize);
|
assert (ui < m_iSize);
|
||||||
return m_Vec[ui];
|
return m_Vec[ui];
|
||||||
}
|
}
|
||||||
|
|
||||||
const T& operator[](unsigned int ui) const
|
const T& operator[](unsigned int ui) const
|
||||||
{
|
{
|
||||||
assert (ui < (unsigned int) m_iSize);
|
assert (ui < (unsigned int) m_iSize);
|
||||||
@ -37,10 +60,44 @@ public:
|
|||||||
m_Vec.resize(s);
|
m_Vec.resize(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resize(int s, bool bCompact = false)
|
||||||
|
{
|
||||||
|
// new size
|
||||||
|
m_iSize = s;
|
||||||
|
|
||||||
|
// if compacting is not desired, no need to shrink vector
|
||||||
|
if (m_iSize < m_Vec.size())
|
||||||
|
{
|
||||||
|
if (!bCompact)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Vec.resize(s);
|
||||||
|
}
|
||||||
|
|
||||||
void set(unsigned int ui, const T &t)
|
void set(unsigned int ui, const T &t)
|
||||||
{
|
{
|
||||||
assert (ui < (unsigned int) m_iSize);
|
assert (ui < (unsigned int) m_iSize);
|
||||||
m_Vec.set(ui, t);
|
m_Vec[ui] = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
T * request()
|
||||||
|
{
|
||||||
|
m_iSize++;
|
||||||
|
if (m_iSize >= m_Vec.size())
|
||||||
|
grow();
|
||||||
|
|
||||||
|
return &m_Vec[m_iSize-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void grow()
|
||||||
|
{
|
||||||
|
int new_size = m_Vec.size() * 2;
|
||||||
|
if (!new_size) new_size = 1;
|
||||||
|
|
||||||
|
reserve(new_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(const T &t)
|
void push_back(const T &t)
|
||||||
@ -51,12 +108,12 @@ public:
|
|||||||
{
|
{
|
||||||
int size = m_iSize;
|
int size = m_iSize;
|
||||||
m_iSize = size_p1;
|
m_iSize = size_p1;
|
||||||
m_Vec.set(size, t);
|
set(size, t);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// need more space
|
// need more space
|
||||||
reserve(m_Vec.size() * 2);
|
grow();
|
||||||
|
|
||||||
// call recursive
|
// call recursive
|
||||||
push_back(t);
|
push_back(t);
|
||||||
@ -102,10 +159,11 @@ public:
|
|||||||
m_iSize = 0;
|
m_iSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int size() const {return m_iSize;}
|
int size() const {return m_iSize;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vector<T> m_Vec;
|
std::vector<T> m_Vec;
|
||||||
|
|
||||||
// working size
|
// working size
|
||||||
int m_iSize;
|
int m_iSize;
|
||||||
|
@ -3,16 +3,12 @@
|
|||||||
#include "register_types.h"
|
#include "register_types.h"
|
||||||
|
|
||||||
#include "core/class_db.h"
|
#include "core/class_db.h"
|
||||||
#include "lroom.h"
|
|
||||||
#include "lroom_manager.h"
|
#include "lroom_manager.h"
|
||||||
#include "lportal.h"
|
|
||||||
|
|
||||||
|
|
||||||
void register_lportal_types() {
|
void register_lportal_types() {
|
||||||
|
|
||||||
ClassDB::register_class<LRoom>();
|
|
||||||
ClassDB::register_class<LRoomManager>();
|
ClassDB::register_class<LRoomManager>();
|
||||||
ClassDB::register_class<LPortal>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void unregister_lportal_types() {
|
void unregister_lportal_types() {
|
||||||
|
Loading…
Reference in New Issue
Block a user