First working test version

This commit is contained in:
lawnjelly 2019-09-12 15:51:33 +01:00 committed by GitHub
parent 829dcb8e13
commit 726412a97b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 377 additions and 46 deletions

93
CoBitField_Dynamic.cpp Normal file
View File

@ -0,0 +1,93 @@
#include "CoBitField_Dynamic.h"
#include <string.h>
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<m_uiNumBytes; n++)
{
m_pucData[n] = ~m_pucData[n];
}
}
////////////////////////////////////////////////////////////////////////////
} // namespace end

91
CoBitField_Dynamic.h Normal file
View File

@ -0,0 +1,91 @@
#pragma once
#include <assert.h>
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

1
SCsub
View File

@ -6,6 +6,7 @@ sources = [
"lroom.cpp",
"lroom_manager.cpp",
"lportal.cpp",
"CoBitField_Dynamic.cpp",
]
module_env = env.Clone()

View File

@ -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<Plane> &planes) const
{
// short version
const Vector<Vector3> &pts = m_ptsWorld;
int nPoints = pts.size();
// ERR_FAIL_COND(nPoints < 3);
Plane p;
for (int n=1; n<nPoints; n++)
{
p = Plane(ptCam, pts[n], pts[n-1]);
planes.push_back(p);
}
}
LPortal::eClipResult LPortal::ClipWithPlane(const Plane &p) const
{
int nOutside = 0;
@ -93,7 +116,7 @@ void LPortal::Link(LRoom * pParentRoom)
String szRoom = FindNameAfter(this, "lportal_");
print_line("LPortal::Link to room " + szRoom);
print("LPortal::Link to room " + szRoom);
// find the room group
Spatial * pGroup = Object::cast_to<Spatial>(pParentRoom->get_parent());
@ -139,13 +162,13 @@ void LPortal::CreateGeometry(PoolVector<Vector3> 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<nPoints; n++)
{
m_ptsLocal.set(n, p_vertices[n]);
Variant pt = p_vertices[n];
print_line("\t\t" + itos(n) + "\t: " + pt);
print("\t\t" + itos(n) + "\t: " + pt);
}
SortVertsClockwise();
@ -250,12 +273,12 @@ void LPortal::CalculateLocalPoints()
Transform tr = get_transform();
print_line("\tCalculateLocalPoints");
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_line("\t\t" + itos(n) + "\t: " + pt);
print("\t\t" + itos(n) + "\t: " + pt);
}
}
@ -267,18 +290,18 @@ void LPortal::CalculateWorldPoints()
Transform tr = get_global_transform();
print_line("\tCalculateWorldPoints");
print("\tCalculateWorldPoints");
for (int n=0; n<nPoints; n++)
{
m_ptsWorld.set(n, tr.xform(m_ptsLocal[n]));
Variant pt = m_ptsWorld[n];
print_line("\t\t" + itos(n) + "\t: " + pt);
print("\t\t" + itos(n) + "\t: " + pt);
}
}
void LPortal::CopyReversedGeometry(const LPortal &source)
{
print_line("CopyReversedGeometry");
print("CopyReversedGeometry");
// points are the same but reverse winding order
int nPoints = source.m_ptsWorld.size();
@ -289,7 +312,7 @@ void LPortal::CopyReversedGeometry(const LPortal &source)
{
m_ptsWorld.set(n, source.m_ptsWorld[nPoints - n - 1]);
Variant pt = m_ptsWorld[n];
print_line("\t\t" + itos(n) + "\t: " + pt);
print("\t\t" + itos(n) + "\t: " + pt);
}
CalculateLocalPoints();
@ -306,7 +329,7 @@ void LPortal::PlaneFromPoints()
// create plane from points
m_Plane = Plane(m_ptsWorld[0], m_ptsWorld[1], m_ptsWorld[2]);
print_line("Plane normal world space : " + m_Plane);
print("Plane normal world space : " + m_Plane);
// Plane opp = Plane(m_ptsWorld[2], m_ptsWorld[1], m_ptsWorld[0]);
// print_line("Plane opposite : " + opp);
@ -315,7 +338,7 @@ void LPortal::PlaneFromPoints()
bool LPortal::AddRoom(NodePath path)
{
print_line("LPortal::AddRoom path is " + path);
print("LPortal::AddRoom path is " + path);
if (has_node(path))
{

View File

@ -29,16 +29,6 @@
#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.
class LRoom;
class LPortal : public Spatial {
@ -62,6 +52,7 @@ protected:
static void _bind_methods();
LPortal::eClipResult ClipWithPlane(const Plane &p) const;
void AddPlanes(const Vector3 &ptCam, Vector<Plane> &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);
};

View File

@ -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<Plane> &planes, ObjectID portalID_from)
LRoom::LRoom() {
m_LocalRoomID = -1;
}
void LRoom::DetermineVisibility_Recursive(int depth, const LCamera &cam, const Vector<Plane> &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<get_child_count(); n++)
{
// ignore portals
Node * pNode = get_child(n);
LPortal * pPortal = Object::cast_to<LPortal>(pNode);
if (pPortal)
continue;
VisualInstance * pObj = Object::cast_to<VisualInstance>(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<planes.size(); p++)
{
// float dist = planes[p].distance_to(pt);
// print("\t\t\t\t" + itos(p) + " : dist " + String(Variant(dist)));
float r_min, r_max;
bb.project_range_in_plane(planes[p], r_min, r_max);
print("\t\t\t\t" + itos(p) + " : r_min " + String(Variant(r_min)) + ", r_max " + String(Variant(r_max)));
if (r_min > 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<Plane> 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<Mesh> rmesh = pMeshInstance->get_mesh();

16
lroom.h
View File

@ -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<ObjectID> 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<Plane> &planes, ObjectID portalID_from = 0);
void DetermineVisibility_Recursive(int depth, const LCamera &cam, const Vector<Plane> &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);
};

View File

@ -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<Camera>(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<LRoom>(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<Plane> 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<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 = 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<m_room_IDs.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))
{
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);
}

View File

@ -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<ObjectID> 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<int> 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();