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",
|
||||
"lroom.cpp",
|
||||
"lroom_manager.cpp",
|
||||
"lroom_converter.cpp",
|
||||
"lportal.cpp",
|
||||
"lplanes_pool.cpp",
|
||||
"ldob.cpp",
|
||||
@ -12,7 +13,7 @@ sources = [
|
||||
]
|
||||
|
||||
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':
|
||||
# Shared lib compilation
|
||||
|
10
ldob.h
10
ldob.h
@ -2,6 +2,16 @@
|
||||
|
||||
#include "scene/3d/spatial.h"
|
||||
|
||||
|
||||
// static object
|
||||
class LSob
|
||||
{
|
||||
public:
|
||||
ObjectID m_ID; // godot object
|
||||
AABB m_aabb; // world space
|
||||
};
|
||||
|
||||
// dynamic object
|
||||
class LDob
|
||||
{
|
||||
public:
|
||||
|
178
lportal.cpp
178
lportal.cpp
@ -126,86 +126,31 @@ LPortal::eClipResult LPortal::ClipWithPlane(const Plane &p) const
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 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)
|
||||
void LPortal::CreateGeometry(PoolVector<Vector3> p_vertices, const Transform &trans)
|
||||
{
|
||||
int nPoints = p_vertices.size();
|
||||
ERR_FAIL_COND(nPoints < 3);
|
||||
|
||||
m_ptsLocal.resize(nPoints);
|
||||
m_ptsWorld.resize(nPoints);
|
||||
|
||||
print("\tLPortal::CreateGeometry nPoints : " + itos(nPoints));
|
||||
|
||||
for (int n=0; n<nPoints; n++)
|
||||
{
|
||||
m_ptsLocal.set(n, p_vertices[n]);
|
||||
Variant pt = p_vertices[n];
|
||||
print("\t\t" + itos(n) + "\t: " + pt);
|
||||
Vector3 ptWorld = trans.xform(p_vertices[n]);
|
||||
m_ptsWorld.set(n, ptWorld);
|
||||
|
||||
print("\t\t" + itos(n) + "\tLocal : " + Variant(p_vertices[n]) + "\tWorld : " + ptWorld);
|
||||
}
|
||||
|
||||
SortVertsClockwise();
|
||||
|
||||
CalculateWorldPoints();
|
||||
|
||||
PlaneFromPoints();
|
||||
}
|
||||
|
||||
// assume first 3 determine the desired normal
|
||||
void LPortal::SortVertsClockwise()
|
||||
{
|
||||
Vector<Vector3> &verts = m_ptsLocal;
|
||||
Vector<Vector3> &verts = m_ptsWorld;
|
||||
|
||||
// find normal
|
||||
Plane plane = Plane(verts[0], verts[1], verts[2]);
|
||||
@ -237,9 +182,8 @@ void LPortal::SortVertsClockwise()
|
||||
for (int m=n+1; m<nPoints; m++)
|
||||
{
|
||||
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();
|
||||
|
||||
double Angle = a.dot(b);
|
||||
@ -278,7 +222,7 @@ void LPortal::SortVertsClockwise()
|
||||
|
||||
void LPortal::ReverseWindingOrder()
|
||||
{
|
||||
Vector<Vector3> &verts = m_ptsLocal;
|
||||
Vector<Vector3> &verts = m_ptsWorld;
|
||||
Vector<Vector3> copy = verts;
|
||||
|
||||
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)
|
||||
{
|
||||
print("CopyReversedGeometry");
|
||||
// points are the same but reverse winding order
|
||||
int nPoints = source.m_ptsWorld.size();
|
||||
|
||||
m_ptsLocal.resize(nPoints);
|
||||
m_ptsWorld.resize(nPoints);
|
||||
|
||||
for (int n=0; n<nPoints; n++)
|
||||
{
|
||||
m_ptsWorld.set(n, source.m_ptsWorld[nPoints - n - 1]);
|
||||
Variant pt = m_ptsWorld[n];
|
||||
print("\t\t" + itos(n) + "\t: " + pt);
|
||||
print("\t\t" + itos(n) + "\t: " + Variant(m_ptsWorld[n]));
|
||||
}
|
||||
|
||||
CalculateLocalPoints();
|
||||
PlaneFromPoints();
|
||||
}
|
||||
|
||||
@ -355,77 +262,12 @@ void LPortal::PlaneFromPoints()
|
||||
|
||||
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() {
|
||||
// unset
|
||||
m_room_ID = 0;
|
||||
}
|
||||
|
||||
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() {
|
||||
|
||||
m_iRoomNum = -1;
|
||||
}
|
||||
|
||||
|
||||
|
37
lportal.h
37
lportal.h
@ -32,12 +32,8 @@
|
||||
|
||||
class LRoom;
|
||||
|
||||
class LPortal : public Spatial {
|
||||
GDCLASS(LPortal, Spatial);
|
||||
|
||||
friend class LRoom;
|
||||
friend class LRoomManager;
|
||||
private:
|
||||
class LPortal {
|
||||
public:
|
||||
|
||||
enum eClipResult
|
||||
{
|
||||
@ -47,46 +43,31 @@ private:
|
||||
};
|
||||
|
||||
|
||||
ObjectID m_room_ID;
|
||||
NodePath m_room_path;
|
||||
const String &get_name() const {return m_szName;}
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
// linked room, this is the number not godot ID
|
||||
int m_iRoomNum;
|
||||
String m_szName;
|
||||
|
||||
LPortal::eClipResult ClipWithPlane(const Plane &p) const;
|
||||
void AddPlanes(const Vector3 &ptCam, LVector<Plane> &planes) const;
|
||||
|
||||
public:
|
||||
// normal determined by winding order
|
||||
Vector<Vector3> m_ptsWorld;
|
||||
Vector<Vector3> m_ptsLocal;
|
||||
Plane m_Plane;
|
||||
|
||||
|
||||
ObjectID GetLinkedRoomID() const {return m_room_ID;}
|
||||
LRoom * GetLinkedRoom() const;
|
||||
|
||||
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 CreateGeometry(PoolVector<Vector3> p_vertices);
|
||||
void CreateGeometry(PoolVector<Vector3> p_vertices, const Transform &trans);
|
||||
void PlaneFromPoints();
|
||||
|
||||
void CalculateWorldPoints();
|
||||
void CalculateLocalPoints();
|
||||
|
||||
void SortVertsClockwise();
|
||||
void ReverseWindingOrder();
|
||||
public:
|
||||
// useful funcs
|
||||
|
||||
// useful funcs
|
||||
static bool NameStartsWith(Node * pNode, String szSearch);
|
||||
static String FindNameAfter(Node * pNode, String szStart);
|
||||
static void print(String sz);
|
||||
protected:
|
||||
static bool m_bRunning;
|
||||
};
|
||||
|
||||
|
311
lroom.cpp
311
lroom.cpp
@ -27,13 +27,27 @@
|
||||
|
||||
void LRoom::print(String sz)
|
||||
{
|
||||
// print_line(sz);
|
||||
LPortal::print(sz);
|
||||
}
|
||||
|
||||
LRoom::LRoom() {
|
||||
m_LocalRoomID = -1;
|
||||
m_RoomID = -1;
|
||||
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
|
||||
LRoom * LRoom::UpdateDOB(Spatial * pDOB)
|
||||
// returns -1 if no change, or the linked room we are moving into
|
||||
LRoom * LRoom::UpdateDOB(LRoomManager &manager, Spatial * pDOB)
|
||||
{
|
||||
const Vector3 &pt = pDOB->get_global_transform().origin;
|
||||
|
||||
@ -76,114 +90,26 @@ LRoom * LRoom::UpdateDOB(Spatial * pDOB)
|
||||
// slop = 0.0f;
|
||||
|
||||
// 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++)
|
||||
for (int p=0; p<m_iNumPortals; p++)
|
||||
{
|
||||
ObjectID id = m_portal_IDs[p];
|
||||
const LPortal &port = manager.m_Portals[m_iFirstPortal + 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);
|
||||
float dist = port.m_Plane.distance_to(pt);
|
||||
|
||||
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
|
||||
return pPortal->GetLinkedRoom();
|
||||
|
||||
// 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");
|
||||
// }
|
||||
// we want to move into the adjoining room
|
||||
return &manager.Portal_GetLinkedRoom(port);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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)
|
||||
void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, const LCamera &cam, const LVector<Plane> &planes, int portalID_from)
|
||||
{
|
||||
// prevent too much depth
|
||||
if (depth >= 8)
|
||||
@ -199,19 +125,18 @@ void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, cons
|
||||
m_uiFrameTouched = manager.m_uiFrameCounter;
|
||||
|
||||
// show this room and add to visible list of rooms
|
||||
show();
|
||||
BF_visible.SetBit(m_LocalRoomID, true);
|
||||
GetGodotRoom()->show();
|
||||
manager.m_BF_visible_rooms.SetBit(m_RoomID, true);
|
||||
|
||||
// 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
|
||||
Node * pNode = get_child(n);
|
||||
LPortal * pPortal = Object::cast_to<LPortal>(pNode);
|
||||
if (pPortal)
|
||||
continue;
|
||||
const LSob sob = m_SOBs[n];
|
||||
Object * pNode = ObjectDB::get_instance(sob.m_ID);
|
||||
|
||||
VisualInstance * pObj = Object::cast_to<VisualInstance>(pNode);
|
||||
|
||||
// should always be a visual instance, only these are added as SOBs
|
||||
if (pObj)
|
||||
{
|
||||
//Vector3 pt = pObj->get_global_transform().origin;
|
||||
@ -251,36 +176,20 @@ void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, cons
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 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++)
|
||||
for (int p=0; p<m_iNumPortals; p++)
|
||||
{
|
||||
ObjectID id = m_portal_IDs[p];
|
||||
int port_id = m_iFirstPortal + p;
|
||||
|
||||
// ignore if the portal we are looking in from
|
||||
if (id == portalID_from)
|
||||
if (port_id == portalID_from)
|
||||
continue;
|
||||
|
||||
// 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::DetermineVisibility_Recursive : Not a portal");
|
||||
continue;
|
||||
}
|
||||
const LPortal &port = manager.m_Portals[port_id];
|
||||
|
||||
// have we already handled the room on this frame?
|
||||
// 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)
|
||||
continue;
|
||||
|
||||
@ -305,7 +214,7 @@ void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, cons
|
||||
// If it isn't we would need a different strategy
|
||||
for (int l=1; l<planes.size(); l++)
|
||||
{
|
||||
LPortal::eClipResult res = pPortal->ClipWithPlane(planes[l]);
|
||||
LPortal::eClipResult res = port.ClipWithPlane(planes[l]);
|
||||
|
||||
switch (res)
|
||||
{
|
||||
@ -339,152 +248,24 @@ void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, cons
|
||||
new_planes.copy_from(planes);
|
||||
|
||||
// add the planes for the portal
|
||||
pPortal->AddPlanes(cam.m_ptPos, new_planes);
|
||||
port.AddPlanes(cam.m_ptPos, new_planes);
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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 LRoomManager;
|
||||
friend class LRoomConverter;
|
||||
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;
|
||||
|
||||
// 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
|
||||
Vector3 m_ptCentre;
|
||||
AABB m_AABB; // world bound
|
||||
|
||||
// in the Room Manager, NOT the godot object ID
|
||||
int m_LocalRoomID;
|
||||
// ID in the Room Manager, NOT the godot object ID
|
||||
int m_RoomID;
|
||||
|
||||
ObjectID m_GodotID;
|
||||
|
||||
// frame counter when last touched .. prevents handling rooms multiple times
|
||||
unsigned int m_uiFrameTouched;
|
||||
|
||||
String m_szName;
|
||||
|
||||
public:
|
||||
const String &get_name() const {return m_szName;}
|
||||
|
||||
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
|
||||
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);
|
||||
bool RemoveDOB(Node * pDOB);
|
||||
LRoom * UpdateDOB(Spatial * pDOB);
|
||||
// specific
|
||||
LRoom * UpdateDOB(LRoomManager &manager, Spatial * pDOB);
|
||||
|
||||
public:
|
||||
LRoom();
|
||||
Spatial * GetGodotRoom() const;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
// void SetupPortal(LPortal * pPortal);
|
||||
void MakeOppositePortal(LPortal * pPortalFrom, LRoom * pRoomTo);
|
||||
void DetectedPortalMesh(MeshInstance * pMeshInstance, String szLinkRoom);
|
||||
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.
|
||||
|
||||
#include "lroom_manager.h"
|
||||
#include "lportal.h"
|
||||
#include "lroom.h"
|
||||
#include "core/engine.h"
|
||||
#include "scene/3d/camera.h"
|
||||
#include "scene/3d/mesh_instance.h"
|
||||
#include "lroom_converter.h"
|
||||
|
||||
LRoomManager::LRoomManager()
|
||||
{
|
||||
// m_room_curr = 0;
|
||||
m_cameraID = 0;
|
||||
m_uiFrameCounter = 0;
|
||||
}
|
||||
@ -38,14 +36,11 @@ int LRoomManager::FindClosestRoom(const Vector3 &pt) const
|
||||
int closest = -1;
|
||||
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);
|
||||
if (!pRoom)
|
||||
continue;
|
||||
const LRoom &lroom = m_Rooms[n];
|
||||
|
||||
float d = pt.distance_squared_to(pRoom->m_ptCentre);
|
||||
// print_line("\troom " + itos(n) + " dist " + String(Variant(d)));
|
||||
float d = pt.distance_squared_to(lroom.m_ptCentre);
|
||||
|
||||
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());
|
||||
Object *pObj = ObjectDB::get_instance(m_room_IDs[i]);
|
||||
if (!pObj)
|
||||
if ((unsigned int) i >= m_Rooms.size())
|
||||
{
|
||||
WARN_PRINT_ONCE("LRoomManager::GetRoom out of range");
|
||||
return 0;
|
||||
|
||||
LRoom * pRoom = Object::cast_to<LRoom>(pObj);
|
||||
if (!pRoom)
|
||||
return 0;
|
||||
|
||||
return pRoom;
|
||||
}
|
||||
return &m_Rooms[i];
|
||||
}
|
||||
|
||||
int LRoomManager::GetRoomNumFromLRoom(LRoom * pRoom) const
|
||||
LRoom * LRoomManager::GetRoom(int i)
|
||||
{
|
||||
// slow .. use metadata for this
|
||||
int search_id = pRoom->get_instance_id();
|
||||
|
||||
for (int n=0; n<m_room_IDs.size(); n++)
|
||||
if ((unsigned int) i >= m_Rooms.size())
|
||||
{
|
||||
if (m_room_IDs[n] == search_id)
|
||||
return n;
|
||||
WARN_PRINT_ONCE("LRoomManager::GetRoom out of range");
|
||||
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;
|
||||
}
|
||||
|
||||
LRoom * LRoomManager::GetRoomFromDOB(Node * pNode) const
|
||||
LRoom * LRoomManager::GetRoomFromDOB(Node * pNode)
|
||||
{
|
||||
int iRoom = Obj_GetRoomNum(pNode);
|
||||
if (iRoom == -1)
|
||||
@ -113,7 +106,7 @@ LRoom * LRoomManager::GetRoomFromDOB(Node * pNode) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRoom * pRoom = GetRoomNum(iRoom);
|
||||
LRoom * pRoom = GetRoom(iRoom);
|
||||
if (pRoom == 0)
|
||||
{
|
||||
WARN_PRINT_ONCE("LRoomManager::GetRoomFromDOB : pRoom is NULL");
|
||||
@ -138,7 +131,7 @@ void LRoomManager::register_dob(Node * pDOB)
|
||||
if (iRoomNum == -1)
|
||||
return;
|
||||
|
||||
LRoom * pRoom = GetRoomNum(iRoomNum);
|
||||
LRoom * pRoom = GetRoom(iRoomNum);
|
||||
if (!pRoom)
|
||||
return;
|
||||
|
||||
@ -163,12 +156,12 @@ bool LRoomManager::update_dob(Node * pDOB)
|
||||
// is it the camera?
|
||||
//bool bCamera = pDOB->get_instance_id() == m_cameraID;
|
||||
|
||||
LRoom * pNewRoom = pRoom->UpdateDOB(pSpat);
|
||||
LRoom * pNewRoom = pRoom->UpdateDOB(*this, pSpat);
|
||||
|
||||
if (pNewRoom)
|
||||
{
|
||||
// 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);
|
||||
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)
|
||||
{
|
||||
m_cameraID = 0;
|
||||
@ -245,192 +210,10 @@ void LRoomManager::set_camera(Node * pCam)
|
||||
// convert empties and meshes to rooms and portals
|
||||
void LRoomManager::convert()
|
||||
{
|
||||
LPortal::m_bRunning = false;
|
||||
print_line("running convert");
|
||||
|
||||
Convert_Rooms();
|
||||
Convert_Portals();
|
||||
Find_Rooms();
|
||||
LPortal::m_bRunning = true;
|
||||
LRoomConverter conv;
|
||||
conv.Convert(*this);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
@ -440,6 +223,7 @@ void LRoomManager::FrameUpdate()
|
||||
return;
|
||||
}
|
||||
|
||||
// we keep a frame counter to prevent visiting things multiple times on the same frame in recursive functions
|
||||
m_uiFrameCounter++;
|
||||
|
||||
// get the camera desired and make into lcamera
|
||||
@ -450,42 +234,37 @@ void LRoomManager::FrameUpdate()
|
||||
pCamera = Object::cast_to<Camera>(pObj);
|
||||
}
|
||||
else
|
||||
// camera not set
|
||||
// camera not set .. do nothing
|
||||
return;
|
||||
|
||||
// camera not a camera??
|
||||
// camera not a camera?? shouldn't happen but we'll check
|
||||
if (!pCamera)
|
||||
return;
|
||||
|
||||
// if not started
|
||||
// if (!m_room_curr)
|
||||
// return;
|
||||
|
||||
// determine visibility
|
||||
// Object *pObj = ObjectDB::get_instance(m_room_curr);
|
||||
// Which room is the camera currently in?
|
||||
LRoom * pRoom = GetRoomFromDOB(pCamera);
|
||||
// Node * pObj = pCamera->get_parent();
|
||||
|
||||
// if (!pObj)
|
||||
// return;
|
||||
|
||||
// LRoom * pRoom = Object::cast_to<LRoom>(pObj);
|
||||
if (!pRoom)
|
||||
{
|
||||
WARN_PRINT_ONCE("LRoomManager::FrameUpdate : curr room is not an LRoom");
|
||||
//print_line("LRoomManager::FrameUpdate : curr room is not an LRoom");
|
||||
// m_room_curr = 0;
|
||||
WARN_PRINT_ONCE("LRoomManager::FrameUpdate : Camera is not in an LRoom");
|
||||
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();
|
||||
|
||||
// lcamera contains the info needed for culling
|
||||
LCamera cam;
|
||||
cam.m_ptPos = Vector3(0, 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();
|
||||
|
||||
// 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();
|
||||
assert (pool_member != -1);
|
||||
|
||||
@ -494,39 +273,29 @@ void LRoomManager::FrameUpdate()
|
||||
|
||||
// get the camera desired and make into lcamera
|
||||
assert (pCamera);
|
||||
// if (pCamera)
|
||||
{
|
||||
Transform tr = pCamera->get_global_transform();
|
||||
cam.m_ptPos = tr.origin;
|
||||
cam.m_ptDir = tr.basis.get_row(2); // or possibly get_axis .. z is what we want
|
||||
Transform tr = pCamera->get_global_transform();
|
||||
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());
|
||||
}
|
||||
|
||||
pRoom->DetermineVisibility_Recursive(*this, 0, cam, planes, m_BF_visible_rooms);
|
||||
// luckily godot already has a function to return a list of the camera clipping planes
|
||||
planes.copy_from(pCamera->get_frustum());
|
||||
|
||||
// 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
|
||||
// NOTE this could be more efficient
|
||||
for (int n=0; n<m_room_IDs.size(); n++)
|
||||
// NOTE this will be done more efficiently, but is okay to start with
|
||||
for (int n=0; n<m_Rooms.size(); n++)
|
||||
{
|
||||
Object *pObj = ObjectDB::get_instance(m_room_IDs[n]);
|
||||
|
||||
LRoom * pRoom = Object::cast_to<LRoom>(pObj);
|
||||
if (pRoom)
|
||||
if (!m_BF_visible_rooms.GetBit(n))
|
||||
{
|
||||
if (!m_BF_visible_rooms.GetBit(n))
|
||||
{
|
||||
pRoom->hide();
|
||||
}
|
||||
m_Rooms[n].GetGodotRoom()->hide();
|
||||
}
|
||||
}
|
||||
|
||||
// when running, emit less debugging output so as not to choke the IDE
|
||||
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) {
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
// bool bVisible = is_visible_in_tree();
|
||||
// ChangeFlags(SF_INVISIBLE, bVisible == false);
|
||||
// SetProcessing();
|
||||
// turn on process, unless we are in the editor
|
||||
if (!Engine::get_singleton()->is_editor_hint())
|
||||
set_process_internal(true);
|
||||
else
|
||||
set_process_internal(false);
|
||||
|
||||
// // we can't translate string name of Target to a node until we are in the tree
|
||||
// ResolveTargetPath();
|
||||
} break;
|
||||
// case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
|
||||
// FixedUpdate();
|
||||
// } break;
|
||||
case NOTIFICATION_INTERNAL_PROCESS: {
|
||||
FrameUpdate();
|
||||
} 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()
|
||||
{
|
||||
// main functions
|
||||
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("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_unregister"), &LRoomManager::unregister_dob);
|
||||
ClassDB::bind_method(D_METHOD("dob_update"), &LRoomManager::update_dob);
|
||||
ClassDB::bind_method(D_METHOD("dob_teleport"), &LRoomManager::teleport_dob);
|
||||
|
||||
}
|
||||
|
@ -30,58 +30,26 @@
|
||||
#include "lbitfield_dynamic.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 {
|
||||
GDCLASS(LRoomManager, Spatial);
|
||||
|
||||
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;
|
||||
|
||||
// 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;
|
||||
Vector<int> m_VisibleRoomList[2];
|
||||
int m_CurrentVisibleRoomList;
|
||||
// Vector<int> m_VisibleRoomList[2];
|
||||
// int m_CurrentVisibleRoomList;
|
||||
|
||||
// keep a frame counter, to mark when objects have been hit by the visiblity algorithm
|
||||
// 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
|
||||
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 unregister_dob(Node * pDOB);
|
||||
bool update_dob(Node * pDOB);
|
||||
@ -108,25 +79,32 @@ protected:
|
||||
static void _bind_methods();
|
||||
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;
|
||||
private:
|
||||
// one time conversion and setup
|
||||
void Convert_Rooms();
|
||||
bool Convert_Room(Spatial * pNode);
|
||||
void Convert_Portals();
|
||||
void Find_Rooms();
|
||||
|
||||
// helper funcs
|
||||
LRoom * GetRoomNum(int i) const;
|
||||
LRoom * GetRoomFromDOB(Node * pNode) const;
|
||||
int GetRoomNumFromLRoom(LRoom * pRoom) const;
|
||||
const LRoom * GetRoom(int i) const;
|
||||
LRoom * GetRoom(int i);
|
||||
|
||||
LRoom * GetRoomFromDOB(Node * pNode);
|
||||
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;
|
||||
void Obj_SetRoomNum(Node * pNode, int num);
|
||||
|
||||
|
||||
// this is where we do all the culling
|
||||
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
|
||||
|
68
lvector.h
68
lvector.h
@ -1,8 +1,30 @@
|
||||
#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 <assert.h>
|
||||
#include <vector>
|
||||
|
||||
template <class T> class LVector
|
||||
{
|
||||
@ -14,6 +36,7 @@ public:
|
||||
assert (ui < m_iSize);
|
||||
return m_Vec[ui];
|
||||
}
|
||||
|
||||
const T& operator[](unsigned int ui) const
|
||||
{
|
||||
assert (ui < (unsigned int) m_iSize);
|
||||
@ -37,10 +60,44 @@ public:
|
||||
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)
|
||||
{
|
||||
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)
|
||||
@ -51,12 +108,12 @@ public:
|
||||
{
|
||||
int size = m_iSize;
|
||||
m_iSize = size_p1;
|
||||
m_Vec.set(size, t);
|
||||
set(size, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
// need more space
|
||||
reserve(m_Vec.size() * 2);
|
||||
grow();
|
||||
|
||||
// call recursive
|
||||
push_back(t);
|
||||
@ -102,10 +159,11 @@ public:
|
||||
m_iSize = 0;
|
||||
}
|
||||
|
||||
|
||||
int size() const {return m_iSize;}
|
||||
|
||||
private:
|
||||
Vector<T> m_Vec;
|
||||
std::vector<T> m_Vec;
|
||||
|
||||
// working size
|
||||
int m_iSize;
|
||||
|
@ -3,16 +3,12 @@
|
||||
#include "register_types.h"
|
||||
|
||||
#include "core/class_db.h"
|
||||
#include "lroom.h"
|
||||
#include "lroom_manager.h"
|
||||
#include "lportal.h"
|
||||
|
||||
|
||||
void register_lportal_types() {
|
||||
|
||||
ClassDB::register_class<LRoom>();
|
||||
ClassDB::register_class<LRoomManager>();
|
||||
ClassDB::register_class<LPortal>();
|
||||
}
|
||||
|
||||
void unregister_lportal_types() {
|
||||
|
Loading…
Reference in New Issue
Block a user