diff --git a/CoBitField_Dynamic.cpp b/CoBitField_Dynamic.cpp new file mode 100644 index 0000000..2214fee --- /dev/null +++ b/CoBitField_Dynamic.cpp @@ -0,0 +1,93 @@ +#include "CoBitField_Dynamic.h" + +#include + + +namespace Core { // namespace start + +void CoBitField_Dynamic::Initialize() {assert (0 && "CoBitField_Dynamic : Does not support Initialize, use IT version");} +void CoBitField_Dynamic::Terminate() {assert (0 && "CoBitField_Dynamic : Does not support Terminate, use IT version");} + + +void CoBitField_Dynamic_IT::Initialize() +{ + Initialize_Do(); +} + +void CoBitField_Dynamic_IT::Terminate() +{ + Terminate_Do(); +} + + +void CoBitField_Dynamic_IT::Initialize_Do() +{ + memset (this, 0, sizeof (CoBitField_Dynamic)); +} + +void CoBitField_Dynamic_IT::Terminate_Do() +{ + Destroy(); +} + +void CoBitField_Dynamic_IT::CopyFrom(const CoBitField_Dynamic_IT &source) +{ + Create(source.GetNumBits(), false); + memcpy(m_pucData, source.GetData(), source.GetNumBytes()); +} + + +void CoBitField_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 CoBitField_Dynamic_IT::Destroy() +{ + if (m_pucData) + { + delete[] m_pucData; + m_pucData = 0; + } + + memset (this, 0, sizeof (CoBitField_Dynamic)); +} + + +void CoBitField_Dynamic_IT::Blank(bool bSetOrZero) +{ + if (bSetOrZero) + { + memset(m_pucData, 255, m_uiNumBytes); + } + else + { + memset(m_pucData, 0, m_uiNumBytes); + } +} + +void CoBitField_Dynamic_IT::Invert() +{ + for (unsigned int n=0; n + +namespace Core { // namespace start + +class CoBitField_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. + CoBitField_Dynamic_IT& operator=(const CoBitField_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 CoBitField_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 CoBitField_Dynamic : public CoBitField_Dynamic_IT +{ +public: + // call initialize and terminate automatically + CoBitField_Dynamic(unsigned int uiNumBits) {Initialize_Do(); Create(uiNumBits);} + CoBitField_Dynamic() {Initialize_Do();} + ~CoBitField_Dynamic() {Terminate_Do();} + + // disallow explicit calls + void Initialize(); + void Terminate(); +}; + + +////////////////////////////////////////////////////////// +inline unsigned int CoBitField_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 CoBitField_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 diff --git a/SCsub b/SCsub index dec7376..6785a19 100644 --- a/SCsub +++ b/SCsub @@ -6,6 +6,7 @@ sources = [ "lroom.cpp", "lroom_manager.cpp", "lportal.cpp", + "CoBitField_Dynamic.cpp", ] module_env = env.Clone() diff --git a/lportal.cpp b/lportal.cpp index 7f27bbe..566d89c 100644 --- a/lportal.cpp +++ b/lportal.cpp @@ -22,6 +22,10 @@ #include "core/engine.h" #include "lroom.h" +void LPortal::print(String sz) +{ +// print_line(sz); +} bool LPortal::NameStartsWith(Node * pNode, String szSearch) { @@ -50,12 +54,31 @@ String LPortal::FindNameAfter(Node * pNode, String szStart) String name = pNode->get_name(); szRes = name.substr(szStart.length()); - print_line("\t\tNameAfter is " + szRes); + print("\t\tNameAfter is " + szRes); return szRes; } ////////////////////////////////////////////////////////// +// add clipping planes to the vector formed by each portal edge and the camera +void LPortal::AddPlanes(const Vector3 &ptCam, Vector &planes) const +{ + // short version + const Vector &pts = m_ptsWorld; + + int nPoints = pts.size(); +// ERR_FAIL_COND(nPoints < 3); + + Plane p; + + for (int n=1; n(pParentRoom->get_parent()); @@ -139,13 +162,13 @@ void LPortal::CreateGeometry(PoolVector p_vertices) m_ptsLocal.resize(nPoints); m_ptsWorld.resize(nPoints); - print_line("\tLPortal::CreateGeometry nPoints : " + itos(nPoints)); + print("\tLPortal::CreateGeometry nPoints : " + itos(nPoints)); for (int n=0; n &planes) const; public: // normal determined by winding order @@ -93,6 +84,7 @@ private: public: static bool NameStartsWith(Node * pNode, String szSearch); static String FindNameAfter(Node * pNode, String szStart); + static void print(String sz); }; diff --git a/lroom.cpp b/lroom.cpp index d4361d8..721f7e9 100644 --- a/lroom.cpp +++ b/lroom.cpp @@ -22,24 +22,82 @@ #include "core/engine.h" #include "scene/3d/mesh_instance.h" #include "lportal.h" +#include "CoBitField_Dynamic.h" - -LRoom::LRoom() { +void LRoom::print(String sz) +{ +// print_line(sz); } -void LRoom::DetermineVisibility_Recursive(int depth, const LCamera &cam, const Vector &planes, ObjectID portalID_from) +LRoom::LRoom() { + m_LocalRoomID = -1; +} + +void LRoom::DetermineVisibility_Recursive(int depth, const LCamera &cam, const Vector &planes, Core::CoBitField_Dynamic &BF_visible, ObjectID portalID_from) { // prevent too much depth if (depth >= 8) { - print_line("\t\t\tDEPTH LIMIT REACHED"); + print("\t\t\tDEPTH LIMIT REACHED"); return; } - print_line("DetermineVisibility_Recursive from " + get_name()); + print("DetermineVisibility_Recursive from " + get_name()); + + // show this room and add to visible list of rooms + show(); + BF_visible.SetBit(m_LocalRoomID, true); // clip all objects in this room to the clipping planes - // NYI + for (int n=0; n(pNode); + if (pPortal) + continue; + + VisualInstance * pObj = Object::cast_to(pNode); + if (pObj) + { + Vector3 pt = pObj->get_global_transform().origin; + + bool bShow = true; + + + // estimate the radius .. for now + AABB bb = pObj->get_transformed_aabb(); + + print("\t\t\tculling object " + pObj->get_name()); + + for (int p=0; p 0.0f) + { + bShow = false; + break; + } + } + + if (bShow) + pObj->show(); + else + pObj->hide(); + + } + } + + + // go through each portal out of here int nPortals = m_portal_IDs.size(); @@ -67,14 +125,14 @@ void LRoom::DetermineVisibility_Recursive(int depth, const LCamera &cam, const V } const Vector3 &portal_normal = pPortal->m_Plane.normal; - print_line("\ttesting portal " + pPortal->get_name() + " normal " + portal_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_line("\t\tportal culled (wrong direction) dot is " + String(vd)); + print("\t\tportal culled (wrong direction) dot is " + String(vd)); continue; } @@ -102,7 +160,7 @@ void LRoom::DetermineVisibility_Recursive(int depth, const LCamera &cam, const V // this portal is culled if (overall_res == LPortal::eClipResult::CLIP_OUTSIDE) { - print_line("\t\tportal culled (outside planes)"); + print("\t\tportal culled (outside planes)"); continue; } @@ -110,12 +168,12 @@ void LRoom::DetermineVisibility_Recursive(int depth, const LCamera &cam, const V Vector new_planes = planes; // add the planes for the portal - // NYI + pPortal->AddPlanes(cam.m_ptPos, new_planes); // get the room pointed to by the portal LRoom * pLinkedRoom = pPortal->GetLinkedRoom(); if (pLinkedRoom) - pLinkedRoom->DetermineVisibility_Recursive(depth + 1, cam, new_planes, id); + pLinkedRoom->DetermineVisibility_Recursive(depth + 1, cam, new_planes, BF_visible, id); } } @@ -125,7 +183,7 @@ void LRoom::DetermineVisibility_Recursive(int depth, const LCamera &cam, const V // which will be auto converted to LPortals with this method void LRoom::DetectPortalMeshes() { - print_line("DetectPortalMeshes"); + print("DetectPortalMeshes"); bool bFoundOne = true; @@ -158,7 +216,7 @@ void LRoom::DetectPortalMeshes() void LRoom::DetectedPortalMesh(MeshInstance * pMeshInstance, String szLinkRoom) { - print_line("\tDetected PortalMesh"); + print("\tDetected PortalMesh"); Ref rmesh = pMeshInstance->get_mesh(); diff --git a/lroom.h b/lroom.h index 6230072..303bc2f 100644 --- a/lroom.h +++ b/lroom.h @@ -30,14 +30,7 @@ #include "scene/3d/spatial.h" -// Smooth node allows fixed timestep interpolation without having to write any code. -// It requires a proxy node (which is moved on physics tick), e.g. a rigid body or manually moved spatial.. -// and instead of having MeshInstance as a child of this, you add Smooth node to another part of the scene graph, -// make the MeshInstance a child of the smooth node, then choose the proxy as the target for the smooth node. - -// Note that in the special case of manually moving the proxy to a completely new location, you should call -// 'teleport' on the smooth node after setting the proxy node transform. This will ensure that the current AND -// previous transform records are reset, so it moves instantaneously. +namespace Core {class CoBitField_Dynamic;} class LPortal; class MeshInstance; @@ -55,10 +48,14 @@ class LRoom : public Spatial { GDCLASS(LRoom, Spatial); friend class LPortal; + friend class LRoomManager; private: // a quick list of object IDs of child portals of this room Vector m_portal_IDs; + // in the Room Manager, NOT the godot object ID + int m_LocalRoomID; + protected: static void _bind_methods(); @@ -71,7 +68,7 @@ public: void MakePortalQuickList(); // main function - void DetermineVisibility_Recursive(int depth, const LCamera &cam, const Vector &planes, ObjectID portalID_from = 0); + void DetermineVisibility_Recursive(int depth, const LCamera &cam, const Vector &planes, Core::CoBitField_Dynamic &BF_visible, ObjectID portalID_from = 0); // specific public: @@ -83,6 +80,7 @@ private: // void SetupPortal(LPortal * pPortal); void MakeOppositePortal(LPortal * pPortalFrom, LRoom * pRoomTo); void DetectedPortalMesh(MeshInstance * pMeshInstance, String szLinkRoom); + static void print(String sz); }; diff --git a/lroom_manager.cpp b/lroom_manager.cpp index 93476b5..bbea7ce 100644 --- a/lroom_manager.cpp +++ b/lroom_manager.cpp @@ -22,13 +22,32 @@ #include "lportal.h" #include "lroom.h" #include "core/engine.h" +#include "scene/3d/camera.h" LRoomManager::LRoomManager() { m_room_curr = 0; + m_cameraID = 0; } +void LRoomManager::set_camera(Node * pCam) +{ + m_cameraID = 0; + + if (!pCam) + return; + + Camera * pCamera = Object::cast_to(pCam); + if (!pCamera) + { + WARN_PRINT("Not a camera"); + return; + } + + m_cameraID = pCam->get_instance_id(); +} + // convert empties and meshes to rooms and portals void LRoomManager::convert() { @@ -52,7 +71,10 @@ void LRoomManager::Find_Rooms() // don't want to handle already converted rooms LRoom * pRoom = Object::cast_to(pChild); if (pRoom) + { + pRoom->m_LocalRoomID = m_room_IDs.size(); m_room_IDs.push_back(pRoom->get_instance_id()); + } } m_room_curr = 0; @@ -63,6 +85,9 @@ 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()); } void LRoomManager::Convert_Rooms() @@ -176,6 +201,12 @@ bool LRoomManager::Convert_Room(Spatial * pNode) void LRoomManager::FrameUpdate() { + if (Engine::get_singleton()->is_editor_hint()) + { + WARN_PRINT_ONCE("LRoomManager::FrameUpdate should not be called in editor"); + return; + } + // if not started if (!m_room_curr) return; @@ -195,18 +226,51 @@ void LRoomManager::FrameUpdate() return; } + m_BF_visible_rooms.Blank(); + LCamera cam; cam.m_ptPos = Vector3(0, 0, 0); cam.m_ptDir = Vector3 (-1, 0, 0); Vector planes; - pRoom->DetermineVisibility_Recursive(0, cam, planes); + // get the camera desired and make into lcamera + if (m_cameraID) + { + Object *pObj = ObjectDB::get_instance(m_cameraID); + + Camera * pCamera = Object::cast_to(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 = pCamera->get_frustum(); + } + } + + pRoom->DetermineVisibility_Recursive(0, cam, planes, m_BF_visible_rooms); + // 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(pObj); + if (pRoom) + { + if (!m_BF_visible_rooms.GetBit(n)) + { + pRoom->hide(); + } + } + } // only do once for now - m_room_curr = 0; +// m_room_curr = 0; } @@ -219,6 +283,8 @@ void LRoomManager::_notification(int p_what) { // SetProcessing(); 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(); @@ -245,5 +311,6 @@ 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); } diff --git a/lroom_manager.h b/lroom_manager.h index a5fa665..9c70d2d 100644 --- a/lroom_manager.h +++ b/lroom_manager.h @@ -27,6 +27,7 @@ */ #include "scene/3d/spatial.h" +#include "CoBitField_Dynamic.h" class LRoomManager : public Spatial { GDCLASS(LRoomManager, Spatial); @@ -35,12 +36,19 @@ class LRoomManager : public Spatial { Vector m_room_IDs; 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; +// Vector m_VisibleRoomList[2]; +// int m_CurrentVisibleRoomList; public: LRoomManager(); // convert empties and meshes to rooms and portals void convert(); + void set_camera(Node * pCam); protected: static void _bind_methods();