Ver Fonte

Portal/Sector work

Panagiotis Christopoulos Charitos há 10 anos atrás
pai
commit
6401a3578b

+ 1 - 0
include/anki/Scene.h

@@ -9,6 +9,7 @@
 #include "anki/scene/SceneGraph.h"
 #include "anki/scene/LensFlareComponent.h"
 #include "anki/scene/BodyComponent.h"
+#include "anki/scene/Sector.h"
 #include "anki/scene/ModelNode.h"
 #include "anki/scene/SkinNode.h"
 #include "anki/scene/StaticGeometryNode.h"

+ 3 - 1
include/anki/renderer/DebugDrawer.h

@@ -19,6 +19,7 @@ namespace anki {
 
 // Forward
 class Renderer;
+class PortalSectorComponent;
 
 /// @addtogroup renderer
 /// @{
@@ -180,9 +181,10 @@ private:
 
 	void draw(SpatialComponent& sp) const;
 
+	void draw(const PortalSectorComponent& c) const;
+
 	void drawPath(const Path& path) const;
 };
-
 /// @}
 
 } // end namespace anki

+ 2 - 1
include/anki/scene/Common.h

@@ -14,6 +14,7 @@ namespace anki {
 
 // Forward
 class SceneNode;
+class SceneGraph;
 
 /// @addtogroup Scene
 /// @{
@@ -28,7 +29,7 @@ using SceneFrameAllocator = StackAllocator<T>;
 
 /// Scene dictionary
 template<typename T>
-using SceneDictionary = 
+using SceneDictionary =
 	Dictionary<T, SceneAllocator<std::pair<const char*, T>>>;
 /// @}
 

+ 5 - 1
include/anki/scene/SceneComponent.h

@@ -32,6 +32,7 @@ public:
 		INSTANCE,
 		LENS_FLARE,
 		BODY,
+		SECTOR_PORTAL,
 		PLAYER_CONTROLLER,
 		LAST_COMPONENT_ID = PLAYER_CONTROLLER
 	};
@@ -80,7 +81,7 @@ public:
 
 	void setAutomaticCleanup(Bool enable)
 	{
-		m_flags.enableBits(AUTOMATIC_CLEANUP, enable);	
+		m_flags.enableBits(AUTOMATIC_CLEANUP, enable);
 	}
 
 	Bool getAutomaticCleanup() const
@@ -98,6 +99,9 @@ public:
 		return *m_node;
 	}
 
+	SceneGraph& getSceneGraph();
+	const SceneGraph& getSceneGraph() const;
+
 protected:
 	SceneNode* m_node = nullptr;
 	Timestamp m_timestamp; ///< Indicates when an update happened

+ 31 - 3
include/anki/scene/Sector.h

@@ -7,6 +7,7 @@
 #define ANKI_SCENE_SECTOR_H
 
 #include "anki/scene/SceneNode.h"
+#include "anki/scene/SceneComponent.h"
 #include "anki/Collision.h"
 
 namespace anki {
@@ -20,6 +21,20 @@ class SpatialComponent;
 /// @addtogroup scene
 /// @{
 
+/// Dummy component to identify a portal or sector.
+class PortalSectorComponent: public SceneComponent
+{
+public:
+	PortalSectorComponent(SceneNode* node)
+	:	SceneComponent(Type::SECTOR_PORTAL, node)
+	{}
+
+	static Bool classof(const SceneComponent& c)
+	{
+		return c.getType() == Type::SECTOR_PORTAL;
+	}
+};
+
 /// The base for portals and sectors.
 class PortalSectorBase: public SceneNode
 {
@@ -40,9 +55,21 @@ public:
 
 	SectorGroup& getSectorGroup();
 
+	const DArray<Vec4>& getVertices() const
+	{
+		return m_shapeStorage;
+	}
+
+	const DArray<U16>& getVertexIndices() const
+	{
+		return m_vertIndices;
+	}
+
 protected:
 	DArray<Vec4> m_shapeStorage;
 	CollisionShape* m_shape = nullptr;
+	DArray<U16> m_vertIndices; ///< Used in debug draw
+	SpinLock m_mtx;
 };
 
 /// 2 way portal.
@@ -51,6 +78,8 @@ class Portal: public PortalSectorBase
 	friend class SectorGroup;
 
 public:
+	using Base = PortalSectorBase;
+
 	Portal(SceneGraph* scene)
 	:	PortalSectorBase(scene)
 	{}
@@ -80,6 +109,8 @@ class Sector: public PortalSectorBase
 	friend class SectorGroup;
 
 public:
+	using Base = PortalSectorBase;
+
 	/// Default constructor
 	Sector(SceneGraph* scene)
 	:	PortalSectorBase(scene)
@@ -103,9 +134,6 @@ private:
 	List<Portal*> m_portals;
 	List<SpatialComponent*> m_spatials;
 
-	/// Lock the m_spatials cause many threads will update that
-	SpinLock m_lock;
-
 	List<SpatialComponent*>::Iterator findSpatialComponent(
 		SpatialComponent* sp);
 };

+ 10 - 3
src/renderer/Dbg.cpp

@@ -7,6 +7,7 @@
 #include "anki/renderer/Renderer.h"
 #include "anki/resource/ShaderResource.h"
 #include "anki/scene/SceneGraph.h"
+#include "anki/scene/Sector.h"
 #include "anki/scene/Camera.h"
 #include "anki/scene/Light.h"
 #include "anki/util/Logger.h"
@@ -51,7 +52,7 @@ Error Dbg::init(const ConfigSet& initializer)
 	{
 		fbInit.m_colorAttachments[0].m_texture = m_r->getIs()._getRt();
 	}
-	fbInit.m_colorAttachments[0].m_loadOperation = 
+	fbInit.m_colorAttachments[0].m_loadOperation =
 		AttachmentLoadOperation::LOAD;
 
 	err = m_fb.create(&getGrManager(), fbInit);
@@ -106,6 +107,12 @@ Error Dbg::run(CommandBufferHandle& cmdb)
 			m_sceneDrawer->draw(node);
 		}
 
+		if(bitsEnabled(Flag::SECTOR)
+			&& node.tryGetComponent<PortalSectorComponent>())
+		{
+			m_sceneDrawer->draw(node);
+		}
+
 		return ErrorCode::NONE;
 	});
 
@@ -129,7 +136,7 @@ Error Dbg::run(CommandBufferHandle& cmdb)
 
 		Mat4 v = cam.getComponent<FrustumComponent>().getViewMatrix();
 		Mat4 p = cam.getComponent<FrustumComponent>().getProjectionMatrix();
-		Mat4 vp = 
+		Mat4 vp =
 			cam.getComponent<FrustumComponent>().getViewProjectionMatrix();
 
 		Transform t = cam.getComponent<MoveComponent>().getWorldTransform();
@@ -149,7 +156,7 @@ Error Dbg::run(CommandBufferHandle& cmdb)
 		F32 w = a.w();
 		a /= a.w();
 
-		
+
 		Vec2 rr;
 		Vec4 n = t.getOrigin() - sphere.getCenter();
 		Vec4 right = rot.getColumn(1).xyz0().cross(n);

+ 27 - 27
src/renderer/DebugDrawer.cpp

@@ -498,6 +498,12 @@ void SceneDebugDrawer::draw(SceneNode& node)
 		return ErrorCode::NONE;
 	});
 
+	PortalSectorComponent* ps = node.tryGetComponent<PortalSectorComponent>();
+	if(ps)
+	{
+		draw(*ps);
+	}
+
 	(void)err;
 }
 
@@ -525,39 +531,33 @@ void SceneDebugDrawer::draw(SpatialComponent& x) const
 }
 
 //==============================================================================
-#if 0
-void SceneDebugDrawer::draw(const Sector& sector)
+void SceneDebugDrawer::draw(const PortalSectorComponent& c) const
 {
-	// Draw the sector
-	if(sector.getVisibleByMask() == VB_NONE)
-	{
-		m_dbg->setColor(Vec3(1.0, 0.5, 0.5));
-	}
-	else
-	{
-		if(sector.getVisibleByMask() & VB_CAMERA)
-		{
-			m_dbg->setColor(Vec3(0.5, 1.0, 0.5));
-		}
-		else
-		{
-			m_dbg->setColor(Vec3(0.5, 0.5, 1.0));
-		}
-	}
-	CollisionDebugDrawer v(m_dbg);
-	sector.getAabb().accept(v);
+	const SceneNode& node = c.getSceneNode();
+	const PortalSectorBase& psnode = static_cast<const PortalSectorBase&>(node);
 
-	// Draw the portals
 	m_dbg->setColor(Vec3(0.0, 0.0, 1.0));
-	for(const Portal* portal : sector.getSectorGroup().getPortals())
+
+	m_dbg->begin(GL_LINES);
+	const auto& verts = psnode.getVertices();
+	ANKI_ASSERT((psnode.getVertexIndices().getSize() % 3) == 0);
+	for(U i = 0; i < psnode.getVertexIndices().getSize(); i += 3)
 	{
-		if(portal->sectors[0] == &sector || portal->sectors[1] == &sector)
-		{
-			portal->shape.accept(v);
-		}
+		I id0 = psnode.getVertexIndices()[i];
+		I id1 = psnode.getVertexIndices()[i + 1];
+		I id2 = psnode.getVertexIndices()[i + 2];
+
+		m_dbg->pushBackVertex(verts[id0].xyz());
+		m_dbg->pushBackVertex(verts[id1].xyz());
+
+		m_dbg->pushBackVertex(verts[id1].xyz());
+		m_dbg->pushBackVertex(verts[id2].xyz());
+
+		m_dbg->pushBackVertex(verts[id2].xyz());
+		m_dbg->pushBackVertex(verts[id0].xyz());
 	}
+	m_dbg->end();
 }
-#endif
 
 //==============================================================================
 void SceneDebugDrawer::drawPath(const Path& path) const

+ 12 - 0
src/scene/SceneComponent.cpp

@@ -34,4 +34,16 @@ Error SceneComponent::updateReal(SceneNode& node, F32 prevTime, F32 crntTime,
 	return err;
 }
 
+//==============================================================================
+SceneGraph& SceneComponent::getSceneGraph()
+{
+	return m_node->getSceneGraph();
+}
+
+//==============================================================================
+const SceneGraph& SceneComponent::getSceneGraph() const
+{
+	return m_node->getSceneGraph();
+}
+
 } // end namespace anki

+ 16 - 7
src/scene/SceneGraph.cpp

@@ -7,6 +7,7 @@
 #include "anki/scene/Camera.h"
 #include "anki/scene/ModelNode.h"
 #include "anki/scene/InstanceNode.h"
+#include "anki/scene/Sector.h"
 #include "anki/core/Counters.h"
 #include "anki/renderer/Renderer.h"
 #include "anki/physics/PhysicsWorld.h"
@@ -94,14 +95,20 @@ SceneGraph::SceneGraph()
 
 //==============================================================================
 SceneGraph::~SceneGraph()
-{}
+{
+	if(m_sectors)
+	{
+		m_alloc.deleteInstance(m_sectors);
+		m_sectors = nullptr;
+	}
+}
 
 //==============================================================================
 Error SceneGraph::create(
-	AllocAlignedCallback allocCb, 
-	void* allocCbData, 
+	AllocAlignedCallback allocCb,
+	void* allocCbData,
 	U32 frameAllocatorSize,
-	Threadpool* threadpool, 
+	Threadpool* threadpool,
 	ResourceManager* resources,
 	Input* input,
 	const Timestamp* globalTimestamp)
@@ -118,7 +125,7 @@ Error SceneGraph::create(
 	m_input = input;
 
 	m_alloc = SceneAllocator<U8>(
-		allocCb, allocCbData, 
+		allocCb, allocCbData,
 		1024 * 10,
 		1.0,
 		0);
@@ -132,6 +139,8 @@ Error SceneGraph::create(
 		ANKI_LOGE("Scene creation failed");
 	}
 
+	m_sectors = m_alloc.newInstance<SectorGroup>(this);
+
 	return err;
 }
 
@@ -171,7 +180,7 @@ void SceneGraph::unregisterNode(SceneNode* node)
 			break;
 		}
 	}
-	
+
 	ANKI_ASSERT(it != m_nodes.end());
 	m_nodes.erase(m_alloc, it);
 
@@ -215,7 +224,7 @@ SceneNode* SceneGraph::tryFindSceneNode(const CString& name)
 //==============================================================================
 void SceneGraph::deleteNodesMarkedForDeletion()
 {
-	/// Delete all nodes pending deletion. At this point all scene threads 
+	/// Delete all nodes pending deletion. At this point all scene threads
 	/// should have finished their tasks
 	while(m_objectsMarkedForDeletionCount.load() > 0)
 	{

+ 41 - 18
src/scene/Sector.cpp

@@ -29,8 +29,8 @@ PortalSectorBase::~PortalSectorBase()
 		m_shape = nullptr;
 	}
 
-	// Clean collision shape
 	m_shapeStorage.destroy(alloc);
+	m_vertIndices.destroy(alloc);
 }
 
 //==============================================================================
@@ -39,12 +39,14 @@ Error PortalSectorBase::create(const CString& name, const CString& modelFname)
 	ANKI_CHECK(SceneNode::create(name));
 
 	// Create move component
-	SceneComponent* comp = 
-		getSceneAllocator().newInstance<MoveComponent>(this);
+	SceneComponent* comp = getSceneAllocator().newInstance<MoveComponent>(this);
+	addComponent(comp, true);
 
+	// Create portal sector component
+	comp = getSceneAllocator().newInstance<PortalSectorComponent>(this);
 	addComponent(comp, true);
 
-	// Load mesh 
+	// Load mesh
 	StringAuto newFname(getSceneFrameAllocator());
 	getSceneGraph()._getResourceManager().fixResourceFilename(
 		modelFname, newFname);
@@ -56,7 +58,7 @@ Error PortalSectorBase::create(const CString& name, const CString& modelFname)
 	const MeshLoader::Header& header = loader.getHeader();
 	U vertsCount = header.m_totalVerticesCount;
 	PtrSize vertSize = loader.getVertexSize();
-	
+
 	auto alloc = getSceneAllocator();
 	m_shapeStorage.create(alloc, vertsCount);
 
@@ -70,8 +72,19 @@ Error PortalSectorBase::create(const CString& name, const CString& modelFname)
 
 	// Create shape
 	ConvexHullShape* hull = alloc.newInstance<ConvexHullShape>();
+	m_shape = hull;
 	hull->initStorage(&m_shapeStorage[0], vertsCount);
 
+	// Store indices
+	ANKI_ASSERT(
+		header.m_totalIndicesCount * sizeof(U16) == loader.getIndexDataSize());
+	m_vertIndices.create(alloc, header.m_totalIndicesCount);
+	const U16* indicesIn = reinterpret_cast<const U16*>(loader.getIndexData());
+	for(U i = 0; i < header.m_totalIndicesCount; ++i)
+	{
+		m_vertIndices[i] = indicesIn[i];
+	}
+
 	return ErrorCode::NONE;
 }
 
@@ -115,7 +128,7 @@ Portal::~Portal()
 //==============================================================================
 Error Portal::create(const CString& name, const CString& modelFname)
 {
-	ANKI_CHECK(PortalSectorBase::create(name, modelFname));
+	ANKI_CHECK(Base::create(name, modelFname));
 	getSectorGroup().m_portals.pushBack(getSceneAllocator(), this);
 	return ErrorCode::NONE;
 }
@@ -127,7 +140,7 @@ Error Portal::frameUpdate(F32 prevUpdateTime, F32 crntTime)
 	if(move.getTimestamp() == getGlobalTimestamp())
 	{
 		// Move comp updated. Inform the group
-		
+
 		SectorGroup& group = getSectorGroup();
 
 		// Gather the sectors it collides
@@ -160,6 +173,8 @@ Error Portal::frameUpdate(F32 prevUpdateTime, F32 crntTime)
 //==============================================================================
 void Portal::tryAddSector(Sector* sector)
 {
+	LockGuard<SpinLock> lock(m_mtx);
+
 	auto it = m_sectors.getBegin();
 	auto end = m_sectors.getEnd();
 	for(; it != end; ++it)
@@ -177,6 +192,8 @@ void Portal::tryAddSector(Sector* sector)
 //==============================================================================
 void Portal::tryRemoveSector(Sector* sector)
 {
+	LockGuard<SpinLock> lock(m_mtx);
+
 	auto it = m_sectors.getBegin();
 	auto end = m_sectors.getEnd();
 	for(; it != end; ++it)
@@ -239,6 +256,7 @@ Error Sector::create(const CString& name, const CString& modelFname)
 void Sector::tryAddPortal(Portal* portal)
 {
 	ANKI_ASSERT(portal);
+	LockGuard<SpinLock> lock(m_mtx);
 
 	auto it = m_portals.getBegin();
 	auto end = m_portals.getEnd();
@@ -258,6 +276,7 @@ void Sector::tryAddPortal(Portal* portal)
 void Sector::tryRemovePortal(Portal* portal)
 {
 	ANKI_ASSERT(portal);
+	LockGuard<SpinLock> lock(m_mtx);
 
 	auto it = m_portals.getBegin();
 	auto end = m_portals.getEnd();
@@ -275,6 +294,7 @@ void Sector::tryRemovePortal(Portal* portal)
 void Sector::tryAddSpatialComponent(SpatialComponent* sp)
 {
 	ANKI_ASSERT(sp);
+	LockGuard<SpinLock> lock(m_mtx);
 
 	// Find sector in spatial
 	auto itsp = sp->getSectorInfo().getBegin();
@@ -285,16 +305,12 @@ void Sector::tryAddSpatialComponent(SpatialComponent* sp)
 		{
 			// Found, return
 #if ANKI_ASSERTIONS
-			LockGuard<SpinLock> g(m_lock);
 			ANKI_ASSERT(findSpatialComponent(sp) != m_spatials.getEnd()
 				&& "Spatial has reference to sector but sector not");
 #endif
 			return;
 		}
 	}
-	
-	// Lock since this might be done from a thread
-	LockGuard<SpinLock> g(m_lock);
 
 	ANKI_ASSERT(findSpatialComponent(sp) == m_spatials.getEnd());
 
@@ -306,7 +322,8 @@ void Sector::tryAddSpatialComponent(SpatialComponent* sp)
 void Sector::tryRemoveSpatialComponent(SpatialComponent* sp)
 {
 	ANKI_ASSERT(sp);
-	
+	LockGuard<SpinLock> g(m_mtx);
+
 	// Find sector in spatial
 	auto itsp = sp->getSectorInfo().getBegin();
 	auto endsp = sp->getSectorInfo().getEnd();
@@ -324,8 +341,6 @@ void Sector::tryRemoveSpatialComponent(SpatialComponent* sp)
 
 		sp->getSectorInfo().erase(getSceneAllocator(), itsp);
 
-		LockGuard<SpinLock> g(m_lock);
-
 		auto it = findSpatialComponent(sp);
 		ANKI_ASSERT(it != m_spatials.getEnd());
 		m_spatials.erase(getSceneAllocator(), it);
@@ -333,7 +348,6 @@ void Sector::tryRemoveSpatialComponent(SpatialComponent* sp)
 	else
 	{
 #if ANKI_ASSERTIONS
-		LockGuard<SpinLock> g(m_lock);
 		ANKI_ASSERT(findSpatialComponent(sp) == m_spatials.getEnd());
 #endif
 	}
@@ -364,7 +378,7 @@ Error Sector::frameUpdate(F32 prevUpdateTime, F32 crntTime)
 	if(move.getTimestamp() == getGlobalTimestamp())
 	{
 		// Move comp updated. Inform the group
-		
+
 		SectorGroup& group = getSectorGroup();
 
 		// Gather the portals it collides
@@ -410,7 +424,7 @@ void SectorGroup::spatialUpdated(SpatialComponent* sp)
 		Bool collide = testCollisionShapes(
 			sector.getBoundingShape(), sp->getSpatialCollisionShape());
 
-		if(collide)	
+		if(collide)
 		{
 			sector.tryAddSpatialComponent(sp);
 		}
@@ -421,6 +435,15 @@ void SectorGroup::spatialUpdated(SpatialComponent* sp)
 	}
 }
 
+//==============================================================================
+SectorGroup::~SectorGroup()
+{
+	auto alloc = m_scene->getAllocator();
+
+	m_sectors.destroy(alloc);
+	m_portals.destroy(alloc);
+}
+
 //==============================================================================
 void SectorGroup::spatialDeleted(SpatialComponent* sp)
 {
@@ -557,7 +580,7 @@ void SectorGroup::prepareForVisibilityTests(const FrustumComponent& frc)
 	if(nodesCount > 0)
 	{
 		std::sort(
-			visibleNodes.getBegin(), 
+			visibleNodes.getBegin(),
 			visibleNodes.getBegin() + nodesCount);
 	}
 }

+ 8 - 3
src/scene/SpatialComponent.cpp

@@ -5,13 +5,15 @@
 
 #include "anki/scene/SpatialComponent.h"
 #include "anki/scene/SceneNode.h"
+#include "anki/scene/Sector.h"
+#include "anki/scene/SceneGraph.h"
 
 namespace anki {
 
 //==============================================================================
 SpatialComponent::SpatialComponent(
-	SceneNode* node, 
-	const CollisionShape* shape, 
+	SceneNode* node,
+	const CollisionShape* shape,
 	Flag flags)
 :	SceneComponent(Type::SPATIAL, node),
 	Bitset<Flag>(flags),
@@ -23,7 +25,9 @@ SpatialComponent::SpatialComponent(
 
 //==============================================================================
 SpatialComponent::~SpatialComponent()
-{}
+{
+	getSceneGraph().getSectorGroup().spatialDeleted(this);
+}
 
 //==============================================================================
 Error SpatialComponent::update(SceneNode&, F32, F32, Bool& updated)
@@ -32,6 +36,7 @@ Error SpatialComponent::update(SceneNode&, F32, F32, Bool& updated)
 	if(updated)
 	{
 		m_shape->computeAabb(m_aabb);
+		getSceneGraph().getSectorGroup().spatialUpdated(this);
 		disableBits(Flag::MARKED_FOR_UPDATE);
 	}
 

+ 247 - 1
src/script/Scene.cpp

@@ -34,7 +34,7 @@ static SceneGraph* getSceneGraph(lua_State* l)
 {
 	LuaBinder* binder = static_cast<LuaBinder*>(lua_getuserdata(l));
 
-	ScriptManager* scriptManager = 
+	ScriptManager* scriptManager =
 		reinterpret_cast<ScriptManager*>(binder->getParent());
 
 	return &scriptManager->_getSceneGraph();
@@ -1579,6 +1579,142 @@ static inline void wrapStaticCollisionNode(lua_State* l)
 	lua_settop(l, 0);
 }
 
+//==============================================================================
+// Portal                                                                      =
+//==============================================================================
+
+//==============================================================================
+static const char* classnamePortal = "Portal";
+
+template<>
+I64 LuaBinder::getWrappedTypeSignature<Portal>()
+{
+	return 7450426072538297652;
+}
+
+template<>
+const char* LuaBinder::getWrappedTypeName<Portal>()
+{
+	return classnamePortal;
+}
+
+//==============================================================================
+/// Pre-wrap method Portal::getSceneNodeBase.
+static inline int pwrapPortalgetSceneNodeBase(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 1);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnamePortal, 7450426072538297652, ud)) return -1;
+	Portal* self = static_cast<Portal*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Call the method
+	SceneNode& ret = *self;
+	
+	// Push return value
+	voidp = lua_newuserdata(l, sizeof(UserData));
+	ud = static_cast<UserData*>(voidp);
+	luaL_setmetatable(l, "SceneNode");
+	ud->m_data = static_cast<void*>(&ret);
+	ud->m_gc = false;
+	ud->m_sig = -2220074417980276571;
+	
+	return 1;
+}
+
+//==============================================================================
+/// Wrap method Portal::getSceneNodeBase.
+static int wrapPortalgetSceneNodeBase(lua_State* l)
+{
+	int res = pwrapPortalgetSceneNodeBase(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Wrap class Portal.
+static inline void wrapPortal(lua_State* l)
+{
+	LuaBinder::createClass(l, classnamePortal);
+	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapPortalgetSceneNodeBase);
+	lua_settop(l, 0);
+}
+
+//==============================================================================
+// Sector                                                                      =
+//==============================================================================
+
+//==============================================================================
+static const char* classnameSector = "Sector";
+
+template<>
+I64 LuaBinder::getWrappedTypeSignature<Sector>()
+{
+	return 2371391302432627552;
+}
+
+template<>
+const char* LuaBinder::getWrappedTypeName<Sector>()
+{
+	return classnameSector;
+}
+
+//==============================================================================
+/// Pre-wrap method Sector::getSceneNodeBase.
+static inline int pwrapSectorgetSceneNodeBase(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 1);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameSector, 2371391302432627552, ud)) return -1;
+	Sector* self = static_cast<Sector*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Call the method
+	SceneNode& ret = *self;
+	
+	// Push return value
+	voidp = lua_newuserdata(l, sizeof(UserData));
+	ud = static_cast<UserData*>(voidp);
+	luaL_setmetatable(l, "SceneNode");
+	ud->m_data = static_cast<void*>(&ret);
+	ud->m_gc = false;
+	ud->m_sig = -2220074417980276571;
+	
+	return 1;
+}
+
+//==============================================================================
+/// Wrap method Sector::getSceneNodeBase.
+static int wrapSectorgetSceneNodeBase(lua_State* l)
+{
+	int res = pwrapSectorgetSceneNodeBase(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Wrap class Sector.
+static inline void wrapSector(lua_State* l)
+{
+	LuaBinder::createClass(l, classnameSector);
+	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapSectorgetSceneNodeBase);
+	lua_settop(l, 0);
+}
+
 //==============================================================================
 // SceneGraph                                                                  =
 //==============================================================================
@@ -1854,6 +1990,112 @@ static int wrapSceneGraphnewStaticCollisionNode(lua_State* l)
 	return 0;
 }
 
+//==============================================================================
+/// Pre-wrap method SceneGraph::newPortal.
+static inline int pwrapSceneGraphnewPortal(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 3);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameSceneGraph, -7754439619132389154, ud)) return -1;
+	SceneGraph* self = static_cast<SceneGraph*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Pop arguments
+	const char* arg0;
+	if(LuaBinder::checkString(l, 2, arg0)) return -1;
+	
+	const char* arg1;
+	if(LuaBinder::checkString(l, 3, arg1)) return -1;
+	
+	// Call the method
+	Portal* ret = newSceneNode<Portal>(self, arg0, arg1);
+	
+	// Push return value
+	if(ANKI_UNLIKELY(ret == nullptr))
+	{
+		lua_pushstring(l, "Glue code returned nullptr");
+		return -1;
+	}
+	
+	voidp = lua_newuserdata(l, sizeof(UserData));
+	ud = static_cast<UserData*>(voidp);
+	luaL_setmetatable(l, "Portal");
+	ud->m_data = static_cast<void*>(ret);
+	ud->m_gc = false;
+	ud->m_sig = 7450426072538297652;
+	
+	return 1;
+}
+
+//==============================================================================
+/// Wrap method SceneGraph::newPortal.
+static int wrapSceneGraphnewPortal(lua_State* l)
+{
+	int res = pwrapSceneGraphnewPortal(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Pre-wrap method SceneGraph::newSector.
+static inline int pwrapSceneGraphnewSector(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 3);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameSceneGraph, -7754439619132389154, ud)) return -1;
+	SceneGraph* self = static_cast<SceneGraph*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Pop arguments
+	const char* arg0;
+	if(LuaBinder::checkString(l, 2, arg0)) return -1;
+	
+	const char* arg1;
+	if(LuaBinder::checkString(l, 3, arg1)) return -1;
+	
+	// Call the method
+	Sector* ret = newSceneNode<Sector>(self, arg0, arg1);
+	
+	// Push return value
+	if(ANKI_UNLIKELY(ret == nullptr))
+	{
+		lua_pushstring(l, "Glue code returned nullptr");
+		return -1;
+	}
+	
+	voidp = lua_newuserdata(l, sizeof(UserData));
+	ud = static_cast<UserData*>(voidp);
+	luaL_setmetatable(l, "Sector");
+	ud->m_data = static_cast<void*>(ret);
+	ud->m_gc = false;
+	ud->m_sig = 2371391302432627552;
+	
+	return 1;
+}
+
+//==============================================================================
+/// Wrap method SceneGraph::newSector.
+static int wrapSceneGraphnewSector(lua_State* l)
+{
+	int res = pwrapSceneGraphnewSector(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
 //==============================================================================
 /// Wrap class SceneGraph.
 static inline void wrapSceneGraph(lua_State* l)
@@ -1864,6 +2106,8 @@ static inline void wrapSceneGraph(lua_State* l)
 	LuaBinder::pushLuaCFuncMethod(l, "newPointLight", wrapSceneGraphnewPointLight);
 	LuaBinder::pushLuaCFuncMethod(l, "newSpotLight", wrapSceneGraphnewSpotLight);
 	LuaBinder::pushLuaCFuncMethod(l, "newStaticCollisionNode", wrapSceneGraphnewStaticCollisionNode);
+	LuaBinder::pushLuaCFuncMethod(l, "newPortal", wrapSceneGraphnewPortal);
+	LuaBinder::pushLuaCFuncMethod(l, "newSector", wrapSceneGraphnewSector);
 	lua_settop(l, 0);
 }
 
@@ -1921,6 +2165,8 @@ void wrapModuleScene(lua_State* l)
 	wrapPointLight(l);
 	wrapSpotLight(l);
 	wrapStaticCollisionNode(l);
+	wrapPortal(l);
+	wrapSector(l);
 	wrapSceneGraph(l);
 	LuaBinder::pushLuaCFunc(l, "getSceneGraph", wrapgetSceneGraph);
 }

+ 33 - 1
src/script/Scene.xml

@@ -35,7 +35,7 @@ static SceneGraph* getSceneGraph(lua_State* l)
 {
 	LuaBinder* binder = static_cast<LuaBinder*>(lua_getuserdata(l));
 
-	ScriptManager* scriptManager = 
+	ScriptManager* scriptManager =
 		reinterpret_cast<ScriptManager*>(binder->getParent());
 
 	return &scriptManager->_getSceneGraph();
@@ -211,6 +211,22 @@ static SceneGraph* getSceneGraph(lua_State* l)
 				</method>
 			</methods>
 		</class>
+		<class name="Portal">
+			<methods>
+				<method name="getSceneNodeBase">
+					<overrideCall>SceneNode&amp; ret = *self;</overrideCall>
+					<return>SceneNode&amp;</return>
+				</method>
+			</methods>
+		</class>
+		<class name="Sector">
+			<methods>
+				<method name="getSceneNodeBase">
+					<overrideCall>SceneNode&amp; ret = *self;</overrideCall>
+					<return>SceneNode&amp;</return>
+				</method>
+			</methods>
+		</class>
 		<class name="SceneGraph">
 			<methods>
 				<method name="newModelNode">
@@ -250,6 +266,22 @@ static SceneGraph* getSceneGraph(lua_State* l)
 					</args>
 					<return>StaticCollisionNode*</return>
 				</method>
+				<method name="newPortal">
+					<overrideCall><![CDATA[Portal* ret = newSceneNode<Portal>(self, arg0, arg1);]]></overrideCall>
+					<args>
+						<arg>const CString&amp;</arg>
+						<arg>const CString&amp;</arg>
+					</args>
+					<return>Portal*</return>
+				</method>
+				<method name="newSector">
+					<overrideCall><![CDATA[Sector* ret = newSceneNode<Sector>(self, arg0, arg1);]]></overrideCall>
+					<args>
+						<arg>const CString&amp;</arg>
+						<arg>const CString&amp;</arg>
+					</args>
+					<return>Sector*</return>
+				</method>
 			</methods>
 		</class>
 	</classes>

+ 14 - 14
testapp/Main.cpp

@@ -41,7 +41,7 @@ App* app;
 ModelNode* horse;
 PerspectiveCamera* cam;
 
-#define NO_PLAYER 0
+#define NO_PLAYER 1
 
 
 //==============================================================================
@@ -100,9 +100,9 @@ Error init()
 			err = scene.newSceneNode<PointLight>(name.c_str(), point);
 			if(err) return err;
 			point->setRadius(0.5);
-			point->setDiffuseColor(Vec4(randFloat(6.0) - 2.0, 
+			point->setDiffuseColor(Vec4(randFloat(6.0) - 2.0,
 				randFloat(6.0) - 2.0, randFloat(6.0) - 2.0, 0.0));
-			point->setSpecularColor(Vec4(randFloat(6.0) - 3.0, 
+			point->setSpecularColor(Vec4(randFloat(6.0) - 3.0,
 				randFloat(6.0) - 3.0, randFloat(6.0) - 3.0, 0.0));
 			point->setLocalOrigin(lpos.xyz0());
 
@@ -147,7 +147,7 @@ Error init()
 
 #if 0
 	// Vase point lights
-	F32 x = 8.5; 
+	F32 x = 8.5;
 	F32 y = 2.25;
 	F32 z = 2.49;
 	Array<Vec3, 4> vaseLightPos = {{Vec3(x, y, -z - 1.4), Vec3(x, y, z),
@@ -165,7 +165,7 @@ Error init()
 		point->setLocalOrigin(lightPos);
 		point->setDiffuseColor(Vec4(3.0, 0.2, 0.0, 0.0));
 		point->setSpecularColor(Vec4(1.0, 1.0, 0.0, 0.0));
-		
+
 		//if(i == 0)
 		{
 		point->loadLensFlare("textures/lens_flare/flares0.ankitex");
@@ -206,7 +206,7 @@ Error init()
 		else
 		{
 			InstanceNode* instance;
-			err = scene.newSceneNode<InstanceNode>( 
+			err = scene.newSceneNode<InstanceNode>(
 				("pefire_inst" + std::to_string(i)).c_str(), instance);
 			if(err) return err;
 
@@ -225,7 +225,7 @@ Error init()
 		}
 
 		/*{
-			scene.newSceneNode(pe, ("pesparks" + std::to_string(i)).c_str(), 
+			scene.newSceneNode(pe, ("pesparks" + std::to_string(i)).c_str(),
 				"particles/sparks.ankipart");
 			pe->setLocalOrigin(lightPos);
 		}*/
@@ -234,7 +234,7 @@ Error init()
 
 #if 0
 	// horse
-	err = scene.newSceneNode<ModelNode>("horse", horse, 
+	err = scene.newSceneNode<ModelNode>("horse", horse,
 		"models/horse/horse.ankimdl");
 	if(err) return err;
 	horse->getComponent<MoveComponent>().setLocalTransform(
@@ -260,7 +260,7 @@ Error init()
 	{
 		ScriptResourcePointer script;
 
-		err = script.load("maps/adis/scene.lua", &resources);
+		err = script.load("maps/techdemo/scene.lua", &resources);
 		if(err) return err;
 
 		err = app->getScriptManager().evalString(script->getSource());
@@ -279,7 +279,7 @@ Error init()
 #if 1
 	{
 		ModelNode* fog;
-		scene.newSceneNode<ModelNode>("fog", fog, 
+		scene.newSceneNode<ModelNode>("fog", fog,
 			"models/fog/volumetric_fog_box.ankimdl");
 		MoveComponent& move = fog->getComponent<MoveComponent>();
 		//move.setLocalOrigin(Vec4(10.0, -19.0, 0.0, 0.0));
@@ -339,7 +339,7 @@ Error mainLoopExtra(App& app, void*, Bool& quit)
 	}
 
 	// move the camera
-	static MoveComponent* mover = 
+	static MoveComponent* mover =
 		&scene.getActiveCamera().getComponent<MoveComponent>();
 
 	if(in.getKey(KeyCode::_1))
@@ -374,7 +374,7 @@ Error mainLoopExtra(App& app, void*, Bool& quit)
 	if(in.getKey(KeyCode::L) == 1)
 	{
 		/*SceneNode& l = scene.findSceneNode("horse");
-		
+
 		BodyComponent* bodyc = l.tryGetComponent<BodyComponent>();
 		if(bodyc)
 		{
@@ -384,9 +384,9 @@ Error mainLoopExtra(App& app, void*, Bool& quit)
 				Transform(pos, Mat3x4::getIdentity(), 1.0));
 		}*/
 
-		scene.newSceneNode<ModelNode>(CString(), horse, 
+		scene.newSceneNode<ModelNode>(CString(), horse,
 			"models/crate0/crate0.ankimdl");
-	
+
 		horse->getComponent<MoveComponent>().enableBits(
 			MoveComponent::Flag::IGNORE_LOCAL_TRANSFORM);
 

+ 56 - 0
tools/scene/Exporter.cpp

@@ -956,6 +956,26 @@ void Exporter::visitNode(const aiNode* ainode)
 			continue;
 		}
 
+		if(name.find("ak_portal") == 0)
+		{
+			// Ignore portals
+			Portal portal;
+			portal.m_meshIndex = meshIndex;
+			portal.m_transform = ainode->mTransformation;
+			m_portals.push_back(portal);
+			continue;
+		}
+
+		if(name.find("ak_sector") == 0)
+		{
+			// Ignore sectors
+			Sector sector;
+			sector.m_meshIndex = meshIndex;
+			sector.m_transform = ainode->mTransformation;
+			m_sectors.push_back(sector);
+			continue;
+		}
+
 		// Find if there is another node with the same mesh-material-group pair
 		std::vector<Node>::iterator it;
 		for(it = m_nodes.begin(); it != m_nodes.end(); ++it)
@@ -1059,6 +1079,42 @@ void Exporter::exportAll()
 			<< name << "\", \"" << fname << "\")\n";
 	}
 
+	//
+	// Export portals
+	//
+	unsigned i = 0;
+	for(const Portal& portal : m_portals)
+	{
+		uint32_t meshIndex = portal.m_meshIndex;
+		exportMesh(*m_scene->mMeshes[meshIndex], nullptr);
+
+		std::string name = getMeshName(getMeshAt(meshIndex));
+		std::string fname = m_rpath + name + ".ankimesh";
+		file << "\nnode = scene:newPortal(\""
+			<< name << i << "\", \"" << fname << "\")\n";
+
+		writeNodeTransform("node", portal.m_transform);
+		++i;
+	}
+
+	//
+	// Export sectors
+	//
+	i = 0;
+	for(const Sector& sector : m_sectors)
+	{
+		uint32_t meshIndex = sector.m_meshIndex;
+		exportMesh(*m_scene->mMeshes[meshIndex], nullptr);
+
+		std::string name = getMeshName(getMeshAt(meshIndex));
+		std::string fname = m_rpath + name + ".ankimesh";
+		file << "\nnode = scene:newSector(\""
+			<< name << i << "\", \"" << fname << "\")\n";
+
+		writeNodeTransform("node", sector.m_transform);
+		++i;
+	}
+
 	//
 	// Export nodes and models.
 	//

+ 11 - 2
tools/scene/Exporter.h

@@ -47,6 +47,15 @@ struct VertexWeight
 	uint32_t m_bonesCount;
 };
 
+class Portal
+{
+public:
+	uint32_t m_meshIndex;
+	aiMatrix4x4 m_transform;
+};
+
+using Sector = Portal;
+
 /// AnKi exporter.
 class Exporter
 {
@@ -67,8 +76,8 @@ public:
 	std::ofstream m_sceneFile;
 
 	std::vector<uint32_t> m_collisionMeshIds;
-	std::vector<uint32_t> m_portalMeshIds;
-	std::vector<uint32_t> m_sectorMeshIds;
+	std::vector<Portal> m_portals;
+	std::vector<Sector> m_sectors;
 
 	/// Load the scene.
 	void load();

+ 24 - 12
tools/scene/ExporterMesh.cpp

@@ -113,7 +113,7 @@ static uint16_t toF16(float f)
 		{
 			m = (m | 0x00800000) >> (1 - e);
 
-			if(m & 0x00001000) 
+			if(m & 0x00001000)
 			{
 				m += 0x00002000;
 			}
@@ -187,7 +187,7 @@ uint32_t toR10G10B10A2Sint(float r, float g, float b, float a)
 
 //==============================================================================
 void Exporter::exportMesh(
-	const aiMesh& mesh, 
+	const aiMesh& mesh,
 	const aiMatrix4x4* transform) const
 {
 	std::string name = mesh.mName.C_Str();
@@ -212,18 +212,30 @@ void Exporter::exportMesh(
 		ERROR("Incorrect vertex count number");
 	}
 
-	if(!mesh.HasPositions()
-		|| !mesh.HasNormals()
-		|| !mesh.HasTangentsAndBitangents()
-		|| !mesh.HasTextureCoords(0))
+	if(!mesh.HasPositions())
 	{
-		ERROR("Missing attribute");
+		ERROR("Missing positions");
+	}
+
+	if(!mesh.HasNormals())
+	{
+		ERROR("Missing normals");
+	}
+
+	if(!mesh.HasTangentsAndBitangents())
+	{
+		ERROR("Missing tangents");
+	}
+
+	if(!mesh.HasTextureCoords(0))
+	{
+		ERROR("Missing UVs");
 	}
 
 	// Write header
 	static const char* magic = "ANKIMES2";
 	memcpy(&header.m_magic, magic, 8);
-	
+
 	header.m_positionsFormat.m_components = ComponentFormat::R32G32B32;
 	header.m_positionsFormat.m_transform = FormatTransform::FLOAT;
 
@@ -256,7 +268,7 @@ void Exporter::exportMesh(
 	for(unsigned i = 0; i < mesh.mNumFaces; i++)
 	{
 		const aiFace& face = mesh.mFaces[i];
-		
+
 		if(face.mNumIndices != 3)
 		{
 			ERROR("For some reason assimp returned wrong number of verts "
@@ -303,9 +315,9 @@ void Exporter::exportMesh(
 		if(m_flipyz)
 		{
 			static const aiMatrix4x4 toLefthanded(
-				1, 0, 0, 0, 
-				0, 0, 1, 0, 
-				0, -1, 0, 0, 
+				1, 0, 0, 0,
+				0, 0, 1, 0,
+				0, -1, 0, 0,
 				0, 0, 0, 1);
 
 			pos = toLefthanded * pos;