mirror of
https://github.com/Relintai/godot-lportal.git
synced 2024-11-11 10:52:09 +01:00
Dynamic objects now working
Code needs cleaning up though, and replacing Vector with LVector, and adding culling for dynamics.
This commit is contained in:
parent
811e6d984f
commit
664e8175bf
3
SCsub
3
SCsub
@ -7,7 +7,8 @@ sources = [
|
||||
"lroom_manager.cpp",
|
||||
"lportal.cpp",
|
||||
"lplanes_pool.cpp",
|
||||
"CoBitField_Dynamic.cpp",
|
||||
"ldob.cpp",
|
||||
"lbitfield_dynamic.cpp",
|
||||
]
|
||||
|
||||
module_env = env.Clone()
|
||||
|
93
lbitfield_dynamic.cpp
Normal file
93
lbitfield_dynamic.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
#include "lbitfield_dynamic.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
namespace Lawn { // namespace start
|
||||
|
||||
void LBitField_Dynamic::Initialize() {assert (0 && "LBitField_Dynamic : Does not support Initialize, use IT version");}
|
||||
void LBitField_Dynamic::Terminate() {assert (0 && "LBitField_Dynamic : Does not support Terminate, use IT version");}
|
||||
|
||||
|
||||
void LBitField_Dynamic_IT::Initialize()
|
||||
{
|
||||
Initialize_Do();
|
||||
}
|
||||
|
||||
void LBitField_Dynamic_IT::Terminate()
|
||||
{
|
||||
Terminate_Do();
|
||||
}
|
||||
|
||||
|
||||
void LBitField_Dynamic_IT::Initialize_Do()
|
||||
{
|
||||
memset (this, 0, sizeof (LBitField_Dynamic));
|
||||
}
|
||||
|
||||
void LBitField_Dynamic_IT::Terminate_Do()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void LBitField_Dynamic_IT::CopyFrom(const LBitField_Dynamic_IT &source)
|
||||
{
|
||||
Create(source.GetNumBits(), false);
|
||||
memcpy(m_pucData, source.GetData(), source.GetNumBytes());
|
||||
}
|
||||
|
||||
|
||||
void LBitField_Dynamic_IT::Create(unsigned int uiNumBits, bool bBlank)
|
||||
{
|
||||
// first delete any initial
|
||||
Destroy();
|
||||
|
||||
m_uiNumBits = uiNumBits;
|
||||
if (uiNumBits)
|
||||
{
|
||||
m_uiNumBytes = (uiNumBits / 8) + 1;
|
||||
|
||||
m_pucData = new unsigned char[m_uiNumBytes];
|
||||
|
||||
if (bBlank)
|
||||
Blank(false);
|
||||
}
|
||||
}
|
||||
|
||||
void LBitField_Dynamic_IT::Destroy()
|
||||
{
|
||||
if (m_pucData)
|
||||
{
|
||||
delete[] m_pucData;
|
||||
m_pucData = 0;
|
||||
}
|
||||
|
||||
memset (this, 0, sizeof (LBitField_Dynamic));
|
||||
}
|
||||
|
||||
|
||||
void LBitField_Dynamic_IT::Blank(bool bSetOrZero)
|
||||
{
|
||||
if (bSetOrZero)
|
||||
{
|
||||
memset(m_pucData, 255, m_uiNumBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(m_pucData, 0, m_uiNumBytes);
|
||||
}
|
||||
}
|
||||
|
||||
void LBitField_Dynamic_IT::Invert()
|
||||
{
|
||||
for (unsigned int n=0; n<m_uiNumBytes; n++)
|
||||
{
|
||||
m_pucData[n] = ~m_pucData[n];
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
} // namespace end
|
91
lbitfield_dynamic.h
Normal file
91
lbitfield_dynamic.h
Normal file
@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace Lawn { // namespace start
|
||||
|
||||
class LBitField_Dynamic_IT
|
||||
{
|
||||
public:
|
||||
// construction
|
||||
void Initialize();
|
||||
void Terminate();
|
||||
|
||||
private:
|
||||
// prevent copying (see effective C++ scott meyers)
|
||||
// there is no implementation for copy constructor, hence compiler will complain if you try to copy.
|
||||
LBitField_Dynamic_IT& operator=(const LBitField_Dynamic_IT&);
|
||||
public:
|
||||
|
||||
// create automatically blanks
|
||||
void Create(unsigned int uiNumBits, bool bBlank = true);
|
||||
void Destroy();
|
||||
|
||||
// public funcs
|
||||
inline unsigned int GetNumBits() const {return m_uiNumBits;}
|
||||
inline unsigned int GetBit(unsigned int uiBit) const;
|
||||
inline void SetBit(unsigned int uiBit, unsigned int bSet);
|
||||
void Blank(bool bSetOrZero = false);
|
||||
void Invert();
|
||||
void CopyFrom(const LBitField_Dynamic_IT &source);
|
||||
|
||||
// loading / saving
|
||||
unsigned char * GetData() {return m_pucData;}
|
||||
const unsigned char * GetData() const {return m_pucData;}
|
||||
unsigned int GetNumBytes() const {return m_uiNumBytes;}
|
||||
|
||||
protected:
|
||||
// member funcs
|
||||
void Initialize_Do();
|
||||
void Terminate_Do();
|
||||
|
||||
// member vars
|
||||
unsigned char * m_pucData;
|
||||
unsigned int m_uiNumBytes;
|
||||
unsigned int m_uiNumBits;
|
||||
};
|
||||
|
||||
class LBitField_Dynamic : public LBitField_Dynamic_IT
|
||||
{
|
||||
public:
|
||||
// call initialize and terminate automatically
|
||||
LBitField_Dynamic(unsigned int uiNumBits) {Initialize_Do(); Create(uiNumBits);}
|
||||
LBitField_Dynamic() {Initialize_Do();}
|
||||
~LBitField_Dynamic() {Terminate_Do();}
|
||||
|
||||
// disallow explicit calls
|
||||
void Initialize();
|
||||
void Terminate();
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
inline unsigned int LBitField_Dynamic_IT::GetBit(unsigned int uiBit) const
|
||||
{
|
||||
assert (m_pucData);
|
||||
unsigned int uiByteNumber = uiBit >> 3; // divide by 8
|
||||
assert (uiByteNumber < m_uiNumBytes);
|
||||
unsigned char uc = m_pucData[uiByteNumber];
|
||||
unsigned int uiBitSet = uc & (1 << (uiBit & 7));
|
||||
return uiBitSet;
|
||||
}
|
||||
|
||||
inline void LBitField_Dynamic_IT::SetBit(unsigned int uiBit, unsigned int bSet)
|
||||
{
|
||||
assert (m_pucData);
|
||||
unsigned int uiByteNumber = uiBit >> 3; // divide by 8
|
||||
assert (uiByteNumber < m_uiNumBytes);
|
||||
unsigned char uc = m_pucData[uiByteNumber];
|
||||
unsigned int uiMask = 1 << (uiBit & 7);
|
||||
if (bSet)
|
||||
{
|
||||
uc = uc | uiMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
uc &= ~uiMask;
|
||||
}
|
||||
m_pucData[uiByteNumber] = uc;
|
||||
}
|
||||
|
||||
} // namespace end
|
9
ldob.h
Normal file
9
ldob.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "scene/3d/spatial.h"
|
||||
|
||||
class LDob
|
||||
{
|
||||
public:
|
||||
ObjectID m_ID;
|
||||
};
|
16
lportal.cpp
16
lportal.cpp
@ -22,11 +22,21 @@
|
||||
#include "core/engine.h"
|
||||
#include "lroom.h"
|
||||
|
||||
|
||||
bool LPortal::m_bRunning = false;
|
||||
|
||||
void LPortal::print(String sz)
|
||||
{
|
||||
// print_line(sz);
|
||||
if (m_bRunning)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
print_line(sz);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LPortal::NameStartsWith(Node * pNode, String szSearch)
|
||||
{
|
||||
int sl = szSearch.length();
|
||||
@ -99,7 +109,7 @@ LPortal::eClipResult LPortal::ClipWithPlane(const Plane &p) const
|
||||
{
|
||||
float d = p.distance_to(m_ptsWorld[n]);
|
||||
|
||||
if (d >= 0.0)
|
||||
if (d >= 0.0f)
|
||||
nOutside++;
|
||||
}
|
||||
|
||||
@ -224,7 +234,7 @@ void LPortal::SortVertsClockwise()
|
||||
double SmallestAngle = -1;
|
||||
int Smallest = -1;
|
||||
|
||||
for (unsigned 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.WhichSideNDLCompatible(m_Verts[m], 0.0f) != CoPlane::NEGATIVE_SIDE)
|
||||
|
@ -36,6 +36,7 @@ class LPortal : public Spatial {
|
||||
GDCLASS(LPortal, Spatial);
|
||||
|
||||
friend class LRoom;
|
||||
friend class LRoomManager;
|
||||
private:
|
||||
|
||||
enum eClipResult
|
||||
@ -80,12 +81,13 @@ private:
|
||||
|
||||
void SortVertsClockwise();
|
||||
void ReverseWindingOrder();
|
||||
|
||||
// useful funcs
|
||||
public:
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
||||
|
188
lroom.cpp
188
lroom.cpp
@ -22,7 +22,7 @@
|
||||
#include "core/engine.h"
|
||||
#include "scene/3d/mesh_instance.h"
|
||||
#include "lportal.h"
|
||||
#include "CoBitField_Dynamic.h"
|
||||
#include "lbitfield_dynamic.h"
|
||||
#include "lroom_manager.h"
|
||||
|
||||
void LRoom::print(String sz)
|
||||
@ -33,9 +33,157 @@ void LRoom::print(String sz)
|
||||
|
||||
LRoom::LRoom() {
|
||||
m_LocalRoomID = -1;
|
||||
m_uiFrameTouched = 0;
|
||||
}
|
||||
|
||||
void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, const LCamera &cam, const LVector<Plane> &planes, Core::CoBitField_Dynamic &BF_visible, ObjectID portalID_from)
|
||||
|
||||
|
||||
void LRoom::AddDOB(Spatial * pDOB)
|
||||
{
|
||||
LDob dob;
|
||||
dob.m_ID = pDOB->get_instance_id();
|
||||
|
||||
m_DOBs.push_back(dob);
|
||||
}
|
||||
|
||||
bool LRoom::RemoveDOB(Node * pDOB)
|
||||
{
|
||||
ObjectID id = pDOB->get_instance_id();
|
||||
|
||||
for (int n=0; n<m_DOBs.size(); n++)
|
||||
{
|
||||
if (m_DOBs[n].m_ID == id)
|
||||
{
|
||||
m_DOBs.remove(n);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// returns -1 if no change, or the objectID of the linked room
|
||||
LRoom * LRoom::UpdateDOB(Spatial * pDOB)
|
||||
{
|
||||
const Vector3 &pt = pDOB->get_global_transform().origin;
|
||||
|
||||
const float slop = 0.2f;
|
||||
|
||||
// the camera can't have slop because we might end up front side of a door without entering the room,
|
||||
// hence can't see into the room through the portal!
|
||||
// if (bCamera)
|
||||
// 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++)
|
||||
{
|
||||
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
|
||||
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");
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// prevent too much depth
|
||||
if (depth >= 8)
|
||||
@ -46,6 +194,10 @@ void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, cons
|
||||
|
||||
print("DetermineVisibility_Recursive from " + get_name());
|
||||
|
||||
// set the frame counter
|
||||
assert (manager.m_uiFrameCounter > m_uiFrameTouched);
|
||||
m_uiFrameTouched = manager.m_uiFrameCounter;
|
||||
|
||||
// show this room and add to visible list of rooms
|
||||
show();
|
||||
BF_visible.SetBit(m_LocalRoomID, true);
|
||||
@ -126,22 +278,32 @@ void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, cons
|
||||
continue;
|
||||
}
|
||||
|
||||
const Vector3 &portal_normal = pPortal->m_Plane.normal;
|
||||
print("\ttesting portal " + pPortal->get_name() + " normal " + portal_normal);
|
||||
// have we already handled the room on this frame?
|
||||
// get the room pointed to by the portal
|
||||
LRoom * pLinkedRoom = pPortal->GetLinkedRoom();
|
||||
if (pLinkedRoom->m_uiFrameTouched == manager.m_uiFrameCounter)
|
||||
continue;
|
||||
|
||||
// const Vector3 &portal_normal = pPortal->m_Plane.normal;
|
||||
// print("\ttesting portal " + pPortal->get_name() + " normal " + portal_normal);
|
||||
|
||||
// direction with the camera? (might not need to check)
|
||||
float dot = cam.m_ptDir.dot(portal_normal);
|
||||
if (dot <= 0.0f)
|
||||
{
|
||||
Variant vd = dot;
|
||||
print("\t\tportal culled (wrong direction) dot is " + String(vd));
|
||||
continue;
|
||||
}
|
||||
// float dot = cam.m_ptDir.dot(portal_normal);
|
||||
// if (dot <= -0.0f) // 0.0
|
||||
// {
|
||||
// Variant vd = dot;
|
||||
// print("\t\tportal culled (wrong direction) dot is " + String(vd));
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// is it culled by the planes?
|
||||
LPortal::eClipResult overall_res = LPortal::eClipResult::CLIP_INSIDE;
|
||||
|
||||
for (int l=0; l<planes.size(); l++)
|
||||
// for portals, we want to ignore the near clipping plane, as we might be right on the edge of a doorway
|
||||
// and still want to look through the portal.
|
||||
// So we are starting this loop from 1, ASSUMING that plane zero is the near clipping plane.
|
||||
// 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]);
|
||||
|
||||
@ -179,8 +341,6 @@ void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, cons
|
||||
// add the planes for the portal
|
||||
pPortal->AddPlanes(cam.m_ptPos, new_planes);
|
||||
|
||||
// get the room pointed to by the portal
|
||||
LRoom * pLinkedRoom = pPortal->GetLinkedRoom();
|
||||
if (pLinkedRoom)
|
||||
pLinkedRoom->DetermineVisibility_Recursive(manager, depth + 1, cam, new_planes, BF_visible, id);
|
||||
|
||||
|
21
lroom.h
21
lroom.h
@ -29,9 +29,10 @@
|
||||
|
||||
#include "scene/3d/spatial.h"
|
||||
#include "lvector.h"
|
||||
#include "ldob.h"
|
||||
|
||||
|
||||
namespace Core {class CoBitField_Dynamic;}
|
||||
namespace Lawn {class LBitField_Dynamic;}
|
||||
|
||||
class LPortal;
|
||||
class LRoomManager;
|
||||
@ -55,13 +56,21 @@ 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
|
||||
Vector<LDob> m_DOBs;
|
||||
|
||||
// Just very rough, room centre for determining start rooms of dobs
|
||||
Vector3 m_ptCentre;
|
||||
|
||||
// in the Room Manager, NOT the godot object ID
|
||||
int m_LocalRoomID;
|
||||
|
||||
// frame counter when last touched .. prevents handling rooms multiple times
|
||||
unsigned int m_uiFrameTouched;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
// initial setup, allows importing portals as meshes from modelling program,
|
||||
// which will be auto converted to LPortals with this method
|
||||
void DetectPortalMeshes();
|
||||
@ -70,8 +79,14 @@ public:
|
||||
void MakePortalQuickList();
|
||||
|
||||
// main function
|
||||
void DetermineVisibility_Recursive(LRoomManager &manager, int depth, const LCamera &cam, const LVector<Plane> &planes, Core::CoBitField_Dynamic &BF_visible, ObjectID portalID_from = 0);
|
||||
void DetermineVisibility_Recursive(LRoomManager &manager, int depth, const LCamera &cam, const LVector<Plane> &planes, Lawn::LBitField_Dynamic &BF_visible, ObjectID portalID_from = 0);
|
||||
|
||||
// dynamic objects
|
||||
// bool UpdateDynamicObject(Node * pDynObj);
|
||||
|
||||
void AddDOB(Spatial * pDOB);
|
||||
bool RemoveDOB(Node * pDOB);
|
||||
LRoom * UpdateDOB(Spatial * pDOB);
|
||||
// specific
|
||||
public:
|
||||
LRoom();
|
||||
|
@ -23,14 +23,204 @@
|
||||
#include "lroom.h"
|
||||
#include "core/engine.h"
|
||||
#include "scene/3d/camera.h"
|
||||
#include "scene/3d/mesh_instance.h"
|
||||
|
||||
LRoomManager::LRoomManager()
|
||||
{
|
||||
m_room_curr = 0;
|
||||
// m_room_curr = 0;
|
||||
m_cameraID = 0;
|
||||
|
||||
m_uiFrameCounter = 0;
|
||||
}
|
||||
|
||||
int LRoomManager::FindClosestRoom(const Vector3 &pt) const
|
||||
{
|
||||
//print_line("FindClosestRoom");
|
||||
int closest = -1;
|
||||
float closest_dist = FLT_MAX;
|
||||
|
||||
for (int n=0; n<m_room_IDs.size(); n++)
|
||||
{
|
||||
LRoom * pRoom = GetRoomNum(n);
|
||||
if (!pRoom)
|
||||
continue;
|
||||
|
||||
float d = pt.distance_squared_to(pRoom->m_ptCentre);
|
||||
// print_line("\troom " + itos(n) + " dist " + String(Variant(d)));
|
||||
|
||||
if (d < closest_dist)
|
||||
{
|
||||
closest = n;
|
||||
closest_dist = d;
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
|
||||
LRoom * LRoomManager::GetRoomNum(int i) const
|
||||
{
|
||||
assert (i < m_room_IDs.size());
|
||||
Object *pObj = ObjectDB::get_instance(m_room_IDs[i]);
|
||||
if (!pObj)
|
||||
return 0;
|
||||
|
||||
LRoom * pRoom = Object::cast_to<LRoom>(pObj);
|
||||
if (!pRoom)
|
||||
return 0;
|
||||
|
||||
return pRoom;
|
||||
}
|
||||
|
||||
int LRoomManager::GetRoomNumFromLRoom(LRoom * pRoom) const
|
||||
{
|
||||
// slow .. use metadata for this
|
||||
int search_id = pRoom->get_instance_id();
|
||||
|
||||
for (int n=0; n<m_room_IDs.size(); n++)
|
||||
{
|
||||
if (m_room_IDs[n] == search_id)
|
||||
return n;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void LRoomManager::Obj_SetRoomNum(Node * pNode, int num)
|
||||
{
|
||||
pNode->set_meta("_lroom", num);
|
||||
|
||||
assert (Obj_GetRoomNum(pNode) == num);
|
||||
}
|
||||
|
||||
int LRoomManager::Obj_GetRoomNum(Node * pNode) const
|
||||
{
|
||||
//assert (pNode->has_meta("_lroom"));
|
||||
Variant v = pNode->get_meta("_lroom");
|
||||
if (v.get_type() == Variant::NIL)
|
||||
return -1;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
LRoom * LRoomManager::GetRoomFromDOB(Node * pNode) const
|
||||
{
|
||||
int iRoom = Obj_GetRoomNum(pNode);
|
||||
if (iRoom == -1)
|
||||
{
|
||||
WARN_PRINT_ONCE("LRoomManager::GetRoomFromDOB : metadata is empty");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRoom * pRoom = GetRoomNum(iRoom);
|
||||
if (pRoom == 0)
|
||||
{
|
||||
WARN_PRINT_ONCE("LRoomManager::GetRoomFromDOB : pRoom is NULL");
|
||||
}
|
||||
return pRoom;
|
||||
}
|
||||
|
||||
|
||||
void LRoomManager::register_dob(Node * pDOB)
|
||||
{
|
||||
print_line("register_dob " + pDOB->get_name());
|
||||
|
||||
Spatial * pSpat = Object::cast_to<Spatial>(pDOB);
|
||||
if (!pSpat)
|
||||
return;
|
||||
|
||||
Vector3 pt = pSpat->get_global_transform().origin;
|
||||
|
||||
int iRoomNum = FindClosestRoom(pt);
|
||||
print_line("register_dob closest room " + itos(iRoomNum));
|
||||
|
||||
if (iRoomNum == -1)
|
||||
return;
|
||||
|
||||
LRoom * pRoom = GetRoomNum(iRoomNum);
|
||||
if (!pRoom)
|
||||
return;
|
||||
|
||||
pRoom->AddDOB(pSpat);
|
||||
|
||||
// save the room ID on the dob metadata
|
||||
Obj_SetRoomNum(pSpat, iRoomNum);
|
||||
}
|
||||
|
||||
|
||||
bool LRoomManager::update_dob(Node * pDOB)
|
||||
{
|
||||
// find the room the object is attached to
|
||||
LRoom * pRoom = GetRoomFromDOB(pDOB);
|
||||
if (!pRoom)
|
||||
return false;
|
||||
|
||||
Spatial * pSpat = Object::cast_to<Spatial>(pDOB);
|
||||
if (!pSpat)
|
||||
return false;
|
||||
|
||||
// is it the camera?
|
||||
//bool bCamera = pDOB->get_instance_id() == m_cameraID;
|
||||
|
||||
LRoom * pNewRoom = pRoom->UpdateDOB(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);
|
||||
|
||||
pRoom->RemoveDOB(pDOB);
|
||||
pNewRoom->AddDOB(pSpat);
|
||||
|
||||
// save the room ID on the dob metadata
|
||||
Obj_SetRoomNum(pSpat, iRoomNum);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LRoomManager::teleport_dob(Node * pDOB)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LRoomManager::unregister_dob(Node * pDOB)
|
||||
{
|
||||
LRoom * pRoom = GetRoomFromDOB(pDOB);
|
||||
pRoom->RemoveDOB(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)
|
||||
{
|
||||
@ -47,16 +237,21 @@ void LRoomManager::set_camera(Node * pCam)
|
||||
}
|
||||
|
||||
m_cameraID = pCam->get_instance_id();
|
||||
|
||||
// use this temporarily to force debug
|
||||
LPortal::m_bRunning = false;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
void LRoomManager::Find_Rooms()
|
||||
@ -78,6 +273,7 @@ void LRoomManager::Find_Rooms()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
m_room_curr = 0;
|
||||
|
||||
// just set current room to first room
|
||||
@ -86,6 +282,7 @@ void LRoomManager::Find_Rooms()
|
||||
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());
|
||||
@ -179,20 +376,55 @@ bool LRoomManager::Convert_Room(Spatial * pNode)
|
||||
// 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();
|
||||
@ -208,22 +440,41 @@ void LRoomManager::FrameUpdate()
|
||||
return;
|
||||
}
|
||||
|
||||
// if not started
|
||||
if (!m_room_curr)
|
||||
m_uiFrameCounter++;
|
||||
|
||||
// get the camera desired and make into lcamera
|
||||
Camera * pCamera = 0;
|
||||
if (m_cameraID)
|
||||
{
|
||||
Object *pObj = ObjectDB::get_instance(m_cameraID);
|
||||
pCamera = Object::cast_to<Camera>(pObj);
|
||||
}
|
||||
else
|
||||
// camera not set
|
||||
return;
|
||||
|
||||
// camera not a camera??
|
||||
if (!pCamera)
|
||||
return;
|
||||
|
||||
// if not started
|
||||
// if (!m_room_curr)
|
||||
// return;
|
||||
|
||||
// determine visibility
|
||||
Object *pObj = ObjectDB::get_instance(m_room_curr);
|
||||
// Object *pObj = ObjectDB::get_instance(m_room_curr);
|
||||
LRoom * pRoom = GetRoomFromDOB(pCamera);
|
||||
// Node * pObj = pCamera->get_parent();
|
||||
|
||||
if (!pObj)
|
||||
return;
|
||||
// if (!pObj)
|
||||
// return;
|
||||
|
||||
LRoom * pRoom = Object::cast_to<LRoom>(pObj);
|
||||
// LRoom * pRoom = Object::cast_to<LRoom>(pObj);
|
||||
if (!pRoom)
|
||||
{
|
||||
WARN_PRINT_ONCE("LRoomManager::FrameUpdate : curr room is not an LRoom");
|
||||
print_line("curr room is not an LRoom");
|
||||
m_room_curr = 0;
|
||||
//print_line("LRoomManager::FrameUpdate : curr room is not an LRoom");
|
||||
// m_room_curr = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -242,19 +493,14 @@ void LRoomManager::FrameUpdate()
|
||||
planes.clear();
|
||||
|
||||
// get the camera desired and make into lcamera
|
||||
if (m_cameraID)
|
||||
assert (pCamera);
|
||||
// if (pCamera)
|
||||
{
|
||||
Object *pObj = ObjectDB::get_instance(m_cameraID);
|
||||
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
|
||||
|
||||
Camera * pCamera = Object::cast_to<Camera>(pObj);
|
||||
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
|
||||
|
||||
planes.copy_from(pCamera->get_frustum());
|
||||
}
|
||||
planes.copy_from(pCamera->get_frustum());
|
||||
}
|
||||
|
||||
pRoom->DetermineVisibility_Recursive(*this, 0, cam, planes, m_BF_visible_rooms);
|
||||
@ -276,6 +522,9 @@ void LRoomManager::FrameUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
LPortal::m_bRunning = true;
|
||||
|
||||
|
||||
// only do once for now
|
||||
// m_room_curr = 0;
|
||||
}
|
||||
@ -317,7 +566,14 @@ void LRoomManager::_notification(int p_what) {
|
||||
|
||||
void LRoomManager::_bind_methods()
|
||||
{
|
||||
ClassDB::bind_method(D_METHOD("convert"), &LRoomManager::convert);
|
||||
ClassDB::bind_method(D_METHOD("set_camera"), &LRoomManager::set_camera);
|
||||
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);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
@ -27,9 +27,46 @@
|
||||
*/
|
||||
|
||||
#include "scene/3d/spatial.h"
|
||||
#include "CoBitField_Dynamic.h"
|
||||
#include "lbitfield_dynamic.h"
|
||||
#include "lplanes_pool.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);
|
||||
|
||||
@ -38,14 +75,18 @@ class LRoomManager : public Spatial {
|
||||
// a quick list of object IDs of child rooms
|
||||
Vector<ObjectID> m_room_IDs;
|
||||
|
||||
ObjectID m_room_curr;
|
||||
// ObjectID m_room_curr;
|
||||
ObjectID m_cameraID;
|
||||
|
||||
// keep track of which rooms are visible, so we can hide ones that aren't hit that were previously on
|
||||
Core::CoBitField_Dynamic m_BF_visible_rooms;
|
||||
Lawn::LBitField_Dynamic m_BF_visible_rooms;
|
||||
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
|
||||
unsigned int m_uiFrameCounter;
|
||||
|
||||
public:
|
||||
LRoomManager();
|
||||
|
||||
@ -56,17 +97,35 @@ 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
|
||||
void register_dob(Node * pDOB);
|
||||
void unregister_dob(Node * pDOB);
|
||||
bool update_dob(Node * pDOB);
|
||||
bool teleport_dob(Node * pDOB);
|
||||
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
void _notification(int p_what);
|
||||
|
||||
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;
|
||||
int FindClosestRoom(const Vector3 &pt) const;
|
||||
|
||||
int Obj_GetRoomNum(Node * pNode) const;
|
||||
void Obj_SetRoomNum(Node * pNode, int num);
|
||||
|
||||
|
||||
void FrameUpdate();
|
||||
};
|
||||
|
||||
|
@ -16,7 +16,7 @@ public:
|
||||
}
|
||||
const T& operator[](unsigned int ui) const
|
||||
{
|
||||
assert (ui < m_iSize);
|
||||
assert (ui < (unsigned int) m_iSize);
|
||||
return m_Vec[ui];
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ public:
|
||||
|
||||
void set(unsigned int ui, const T &t)
|
||||
{
|
||||
assert (ui < m_iSize);
|
||||
assert (ui < (unsigned int) m_iSize);
|
||||
m_Vec.set(ui, t);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user