///////////////////////////////////////////////////////////////////////////////
/// @file deSceneRoom.cpp
///
/// @brief scene-holding structures
///
/// @author Assassin
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Apr 2002
/// @author Assassin
/// @remarks Creation
///
/// @date Mar 2003
/// @author Masterg
/// @remarks Terrain added
///
///////////////////////////////////////////////////////////////////////////////

#include "deScene_priv.hpp"
#include "deMath.hpp"
#include "deCamera.hpp"
#include "dePortal.hpp"
#include "deRender.hpp"
#include "deBrush.hpp"
#include "deBitmap.hpp"

WorldObjectClassImp(deSceneRoom);
WorldObjectClassImp(deSceneSky);
WorldObjectClassImp(deSceneTerrain);
WorldObjectClassImp(deSceneABT);

static long s_SceneRoomWOInterfaceID = -1;
deBoolean IdeSceneRoom_Initialize()
{
	IdeWorldManager * manager = IdeWorld_GetManager();
	s_SceneRoomWOInterfaceID = manager->GetUniqueWOInterfaceID();
	
	if (!WorldObjectRegister(deSceneRoom))
		DEBUGRETURN(deFALSE, "IdeSceneRoom_Initialize: WorldObjectRegister(deSceneRoom) failed");
	
	return deTRUE;
}

void IdeSceneRoom_ShutDown()
{
}

long IdeSceneRoom_GetWOInterfaceID()
{
	return s_SceneRoomWOInterfaceID;
}

DESCENE_API IdeSceneRoom* IdeSceneRoom_CreateRoom()
{
	return new deSceneRoom;
}

DESCENE_API IdeSceneSky* IdeSceneObject_CreateSceneSky()
{
	return new deSceneSky;
}

DESCENE_API IdeSceneTerrain* IdeSceneObject_CreateSceneTerrain()
{
	return new deSceneTerrain;
}

DESCENE_API IdeSceneABT* IdeSceneObject_CreateSceneABT()
{
	return new deSceneABT;
}

#ifdef _DEBUG
#define SHOW_SPHERES (0) // set this to 1 to view "spheres" in debug mode
#else
#define SHOW_SPHERES (0)
#endif

#if SHOW_SPHERES

/*
void MakeSphere(deDouble Radius, LineBrush * LB, deMatrix4 * Transform = NULL)
{
	deVec3d points[13];
	points[0] = deMake_Vec3d(Radius, 0, 0);
	points[1] = deMake_Vec3d(0, 0, Radius);
	points[2] = deMake_Vec3d(-Radius, 0, 0);
	points[3] = deMake_Vec3d(0, 0, -Radius);
	points[4] = deMake_Vec3d(Radius, 0, 0);
	points[5] = deMake_Vec3d(0, Radius, 0);
	points[6] = deMake_Vec3d(-Radius, 0, 0);
	points[7] = deMake_Vec3d(0, -Radius, 0);
	points[8] = deMake_Vec3d(0, 0, Radius);
	points[9] = deMake_Vec3d(0, Radius, 0);
	points[10]= deMake_Vec3d(0, 0, -Radius);
	points[11]= deMake_Vec3d(0, -Radius, 0);
	points[12]= deMake_Vec3d(Radius, 0, 0);
	if (Transform)
		Transform->TransformArray(points, points, 13);
	LB->SetCVList(13, points);
}
*/

void MakeSphere(deDouble Radius, IdeLineBrush * LB, deTransform * Transform = NULL)
{
	deVec3d points[25];
	deDouble radsqrt = Radius / sqrt(2);
	points[0] = deMake_Vec3d(Radius, 0, 0);
	points[1] = deMake_Vec3d(radsqrt, 0, radsqrt);
	points[2] = deMake_Vec3d(0, 0, Radius);
	points[3] = deMake_Vec3d(-radsqrt, 0, radsqrt);
	points[4] = deMake_Vec3d(-Radius, 0, 0);
	points[5] = deMake_Vec3d(-radsqrt, 0, -radsqrt);
	points[6] = deMake_Vec3d(0, 0, -Radius);
	points[7] = deMake_Vec3d(radsqrt, 0, -radsqrt);
	points[8] = deMake_Vec3d(Radius, 0, 0);
	points[9] = deMake_Vec3d(radsqrt, radsqrt, 0);
	points[10] = deMake_Vec3d(0, Radius, 0);
	points[11] = deMake_Vec3d(-radsqrt, radsqrt, 0);
	points[12] = deMake_Vec3d(-Radius, 0, 0);
	points[13] = deMake_Vec3d(-radsqrt, -radsqrt, 0);
	points[14] = deMake_Vec3d(0, -Radius, 0);
	points[15] = deMake_Vec3d(0, -radsqrt, radsqrt);
	points[16] = deMake_Vec3d(0, 0, Radius);
	points[17] = deMake_Vec3d(0, radsqrt, radsqrt);
	points[18] = deMake_Vec3d(0, Radius, 0);
	points[19] = deMake_Vec3d(0, radsqrt, -radsqrt);
	points[20]= deMake_Vec3d(0, 0, -Radius);
	points[21] = deMake_Vec3d(0, -radsqrt, -radsqrt);
	points[22]= deMake_Vec3d(0, -Radius, 0);
	points[23] = deMake_Vec3d(radsqrt, -radsqrt, 0);
	points[24]= deMake_Vec3d(Radius, 0, 0);
	if (Transform)
		Transform->TransformArray(points, points, 25);
	LB->SetCVList(25, points);
}
#endif

//=============================================================
// deSceneRoom
//=============================================================
deSceneRoom::deSceneRoom()
{
	m_CurrentPassNum = 0;
	m_Min = m_Max = deZeroVec;
	m_RoomListPtr = NULL;
}

deSceneRoom::~deSceneRoom()
{
	IdeSceneObject * so;
	IdePortal* p;
	void * ptr;

	if (m_RoomListPtr)
	{
		IdeSceneGraph_GetSceneGraphPtr()->RemoveRoom(this);
	}

	ptr = m_Objects.GetNext(NULL, so);
	while (ptr)
	{
		if (so)
		{
			so->RemoveRoomReference(this);
			so->Release();
		}

		ptr = m_Objects.GetNext(ptr, so);
	}

	ptr = m_PortalList.GetNext(NULL, p);
	while (ptr)
	{
		if (p)
			p->Release();
		
		ptr = m_PortalList.GetNext(ptr, p);
	}
}

void* deSceneRoom::GetWOInterface(long interface_id)
{
	if (interface_id == s_SceneRoomWOInterfaceID)
		return (IdeSceneRoom*)(this);
	if (interface_id == 0)
		return (IdeWorldObject*)(this);
	return NULL;
}

void deSceneRoom::SetRoomListPtr(void * ptr)
{
	m_RoomListPtr = ptr;
}

void* deSceneRoom::GetRoomListPtr()
{
	return m_RoomListPtr;
}

long deSceneRoom::Traverse(IdeSceneGraph::deSceneTraversal* Params)
{
	//deFrustum f2;
	IdePlaneFrustum* f2, *tempfrustum;
	int PolysRendered = 0;
	deTList <IdeSceneObject*> olist;
	IdeSceneObject * so;
	deTList <IdePortal*> TPortals;
	IdePortal * portal;
	deVec3d tempvec, camvec;
	deDouble tempdbl;
	void * ptr;
	int CullFlags = Params->CurrentSceneGraph->GetCullFlags();
	
	if (m_CurrentPassNum == Params->CurrentPassNum)
		return 0;
	m_CurrentPassNum = Params->CurrentPassNum;
	f2 = IdeFrustum_CreatePlaneFrustum();
	
	deTransform M(Params->cam->Position());
	M.GetIn(camvec);
	
	// do a specific render for sub-class geometry
	PolysRendered += TraverseRoom(Params);
	
	// cull all the objects we can
	olist = m_Objects;
	if (CullFlags & IdeSceneGraph::deCullFrustum)
		ViewCullObjectList(Params->cam, Params->CurrentFrustum, olist);
	
	//	SG->AddSolidList(olist);
	
	// render all the non-culled objects
	ptr = olist.GetNext(NULL, so);
	while (ptr)
	{
		if (so->GetCurrentPassNum() != m_CurrentPassNum)
		{
			PolysRendered += so->Traverse(Params);

			if (CullFlags & IdeSceneGraph::deCullFarPlaneOptimize)
			{
				// do a computation for a far-plane optimization
				tempvec = so->GetBoundCenter();
				((deTransform&)Params->CurrentTransform).Transform(tempvec, tempvec);
				tempvec -= M.Translation;
				tempdbl = Vec3d_Dot(camvec, tempvec) + so->GetBoundRadius();
				Params->FarthestDistanceFound = max(Params->FarthestDistanceFound, tempdbl);
			}
		}
		ptr = olist.GetNext(ptr, so);
	}
	
	// traverse connected portals
	ptr = m_PortalList.GetNext(NULL, portal);
	while (ptr)
	{
		if (portal->IntersectsFrustum(M, Params->CurrentFrustum))
		{
			if (!Params->CurrentSceneGraph->PortalOccluded(portal))
			{
				if (portal->IsTPortal())
				{
					// T-portals are expensive to use, so cull back-facing T-portals
					deVec3d vec1, vec2;
					long num;
					vec1 = M.Translation;
					vec1 -= *(portal->GetVertices(num));
					portal->GetNormal(vec2);
					if (Vec3d_Dot(vec1, vec2) >= 0)
						TPortals.AddElement(portal);
				}
				else
				{
					// find the room on the other side of the portal
					deWorldID wid;
					deObjectID oid;
					wid = portal->GetLinkWorldID();
					oid = portal->GetLinkObjectID();
					IdeSceneRoom * sn = Params->CurrentSceneGraph->FindRoomWithID(wid, oid);
					DE_ASSERT(sn);
					// set up the clipped frustum
					portal->ClipFrustum(M, Params->CurrentFrustum, f2);
					// now we have to transition the clipped frustum to be the current one, so save the old one
					tempfrustum = Params->CurrentFrustum;
					Params->CurrentFrustum = f2;
					// traverse through the portal to the other room, using the clipped frustum as current
					sn->Traverse(Params);
					// restore the old frustum to the current one
					f2 = Params->CurrentFrustum;
					Params->CurrentFrustum = tempfrustum;
					tempfrustum = NULL;
				}
			}
		}
		ptr = m_PortalList.GetNext(ptr, portal);
	}
	
	deRect rect;
	deTransform TempM1, TempM2;
	ptr = TPortals.GetNext(NULL, portal);
	while (ptr)
	{
		IdeSceneRoom * sn = Params->CurrentSceneGraph->FindRoomWithID(portal->GetLinkWorldID(), portal->GetLinkObjectID());
		portal->ClipFrustum(M, Params->CurrentFrustum, f2);
		
		portal->GetPosition(TempM1);
		portal->GetTransform(TempM2);
		Params->cam->FrustumRect(f2, rect);
		
		// save the current frustum
		tempfrustum = Params->CurrentFrustum;
		Params->CurrentFrustum = f2;
		// increment the portal depth
		Params->CurrentPortalDepth += 1;
		// prepare a batch, including portal geometry, scissor-rect, and transformation
		Params->render->RenderPrepBatch(Params->CurrentPortalDepth, portal, rect, &TempM1, &TempM2);
		// store the current transform
		TempM1 = Params->CurrentTransform;
		((deTransform&)Params->CurrentTransform).Multiply(TempM2, Params->CurrentTransform);
		// render the room on the other side
		sn->Traverse(Params);
		// restore the transform
		Params->CurrentTransform = TempM1;
		// restore the portal depth
		Params->CurrentPortalDepth -= 1;
		// retore the current frustum
		f2 = Params->CurrentFrustum;
		Params->CurrentFrustum = tempfrustum;
		tempfrustum = NULL;
		
		// get the next T-portal for this room
		ptr = TPortals.GetNext(ptr, portal);
	}
	
	f2->Release();
	return PolysRendered;
}

deBoolean deSceneRoom::TestCollision(const IdeCollision::deCollideParams & Params, IdeCollision * Collision)
{
#pragma todo (implement the various different collision detail levels)
	IdeCollision::deCollideInfo CollideInfo;
	IdeSceneObject * so;
	void * ptr;
	deAABB bbox;
	deVec3d Pos, Stop;
	deBoolean CollisionFound = deFALSE;

	Stop = Params.Start;
	Stop += Params.Delta;

	ptr = m_Objects.GetNext(NULL, so);
	while (ptr)
	{
        if (so->GetActivation(IdeSceneObject::activate_collide))
        {
            so->GetWorldAABB(bbox);
            so->GetWorldPos(Pos);
            if (deGeometry::AABBCollision(Params.AABB, Params.Start, Stop, bbox, Pos, 
                CollideInfo.Position, CollideInfo.Normal, CollideInfo.Percent))
            {
                Collision->AddCollision(CollideInfo);
                CollisionFound = deTRUE;
            }
        }

		ptr = m_Objects.GetNext(ptr, so);
	}
	return CollisionFound;
}

long deSceneRoom::GetPassNum()
{
	return m_CurrentPassNum;
}

void deSceneRoom::GetAABB(deVec3d &Min, deVec3d &Max)
{
	Min = m_Min;
	Max = m_Max;
}

void deSceneRoom::SetContents(DWORD contents)
{
	m_Contents = contents;
}

DWORD deSceneRoom::GetContents()
{
	return m_Contents;
}

deBoolean deSceneRoom::AddSceneObject(IdeSceneObject * obj)
{
	if (!obj)
		return deFALSE;

	void * ptr = m_Objects.AddElement(obj);
	if (!ptr)
		return deFALSE;

	if (!obj->AddRoomReference(this, ptr))
		return deFALSE;

	obj->Claim();
	return deTRUE;
}

deBoolean deSceneRoom::RemoveSceneObject(IdeSceneObject * obj)
{
	if (!obj)
		return deFALSE;
	
	void * ptr = obj->GetRoomReference(this);
	if (!ptr || !m_Objects.RemoveElement(ptr))
		return deFALSE;
	
	if (!obj->RemoveRoomReference(this))
		return deFALSE;
	
	obj->Release();
	return deTRUE;
}

deBoolean deSceneRoom::AddPortal(IdePortal * portal)
{
	if (!m_PortalList.AddElement(portal))
		return deFALSE;

	return deTRUE;
}

int deSceneRoom::ViewCullObjectList(IdeCamera * c, const IdePlaneFrustum* f, deTList <IdeSceneObject*> &inout)
{
#pragma todo (test the modifications here)
	int StartLength = inout.Length();
	deVec3d		camfwd, campos, pos, OBB[8];
	deDouble	mindist, maxdist, z, dist, radius;
	deTArray<dePlane>	planes;
	void *ptr;
	IdeSceneObject * so, ** so2;
	int i, j, numplanes;
	bool valid, borderline;
	deTransform M(c->Position());
	deOBB bbox;

	mindist = f->GetMinDist();
	maxdist = f->GetMaxDist();
	numplanes = f->GetNumPlanes();
	planes.ResizeQuick(numplanes);

//#pragma todo(try actually putting the planes in here)
	M.GetIn(camfwd);
	Vec3d_Normalize(camfwd);
	M.Translation = deZeroVec;
	campos = c->Position().Translation;

	for (i = 0; i < numplanes; ++i)
	{
		f->GetPlane(i, planes[i]);
	}

	ptr = inout.GetNext(NULL, so);
	while (ptr)
	{
		valid = false;
		pos = so->GetWorldBoundCenter();
		radius = so->GetBoundRadius();
		z = Vec3d_Dot(camfwd, (pos - campos));
		if (z + radius > mindist && z - radius < maxdist)
		{
			valid = true;
			borderline = false;
			for (i = 0; valid && i < numplanes; i++)
			{
				dist = Vec3d_Dot(planes[i].Norm, pos) - planes[i].Dist;
				// if object on front of plane, in view
				if (dist >= 0)
				{
					continue;
				}
				dist = dist * dist;

				// if object wholly in front of plane, outside view
				if (dist > radius * radius)
					valid = false;
				//borderline = true;
			}
			if (valid && borderline)
			{
				bool outsideplane;
				so->GetWorldOBB(bbox);
				deGeometry::GetPointsOfOBB(bbox, OBB);
				valid = outsideplane = true;
				for (i = 0; outsideplane && i < 8; i++)
				{
					z = Vec3d_Dot(camfwd, (OBB[i] - campos));
					if (z > mindist && z < maxdist)
						outsideplane = false;
				}
				valid = !outsideplane;
				for (i = 0; valid && i < numplanes; i++)
				{
					// we want the object to be in front of the plane, out of view
					outsideplane = true;
					for (j = 0; outsideplane && j < 8; j++)
					{
						dist = Vec3d_Dot(planes[i].Norm, OBB[j]) - planes[i].Dist;
						// if point on frontside of plane, out of view
						if (dist <= 0)
						{
							outsideplane = false;
						}
					}
					// if all points are in front of the plane, it's out of view
					if (outsideplane)
						valid = false;
				}
			}
		}
		if (valid)
			ptr = inout.GetNext(ptr, so);
		else
		{
			ptr = inout.RemoveElementGetNext(ptr, so2);
			if (so2)
				so = *so2;
			else
				so = NULL;
		}
	}

	return inout.Length() - StartLength;
}

struct deSceneRoom_Header_t
{
	short VersionMajor;
	short VersionMinor;
};
static const deSceneRoom_Header_t deSceneRoom_Header = {0,1};
/*
Version 0.1:
October 15, 2002
struct Vec3d { deDouble x,y,z; }
struct IDPair { ushort worldID; ulong objectID; }
struct TransformInfo { Vec3d Translation,L,U,I,Scale; uchar identity;}
struct Portal
	{	IDPair LinkID; 
		MatrixInfo Position; 
		long HasTransform; 
			if (HasTransform) ==> (TransformInfo Transform);
		Vec3d Normal;
		long NumVerts
		Vec3d Vertices[NumVerts]
	}

short		Version_Major
short		Version_Minor
deVec3d		Min
deVec3d		Max
long		NumObjects
IDPair		Objects[NumObjects]
long		NumPortals
Portal		Portals[NumPortals]

Version 0.2:
August 7, 2003
all the same, except following definition
struct TransformInfo
{ Vec3d Translation, L, U, I; }
*/
deBoolean deSceneRoom::Serialize(IdeFile* File)
{
	void *				ptr;
	IdeWorld*			pWorld;
	IdeSceneObject*		pSO;
	IdePortal*			pPortal;
	deWorldID			WorldID;
	deObjectID			ObjectID;
	deTransformInfo		Matrix;
	deVec3d				Vector, *pVec;
	long				length, i, j, k;
	deBoolean TrueValue = deTRUE, FalseValue = deFALSE;

	// header information
	DE3D_STREAM_PUT(File, deSceneRoom_Header.VersionMajor, u16);
	DE3D_STREAM_PUT(File, deSceneRoom_Header.VersionMinor, u16);
	
	// AABB
	DE3D_STREAM_PUT(File, m_Min.x, deDouble);
	DE3D_STREAM_PUT(File, m_Min.y, deDouble);
	DE3D_STREAM_PUT(File, m_Min.z, deDouble);
	DE3D_STREAM_PUT(File, m_Max.x, deDouble);
	DE3D_STREAM_PUT(File, m_Max.y, deDouble);
	DE3D_STREAM_PUT(File, m_Max.z, deDouble);
	
	// number of Scene objects
	length = m_Objects.Length();
	DE3D_STREAM_PUT(File, length, s32);
	
	// the objects themselves
	ptr = m_Objects.GetNext(NULL, pSO);
	i = 0;
	while (ptr && i < length)
	{
		WorldID = 0;
		ObjectID = 0;
		if (pSO)
		{
#pragma todo (decide if these sceneobject references should only be saved if they are in the same world)
			WorldID = pSO->GetWorldID();
			pWorld = IdeWorld_GetManager()->GetWorld(((IdeWorldObject*)this)->GetWorldID());
			if (pWorld)
			{
				WorldID = pWorld->GetLocalIDFromLoadedWorld(WorldID);
				ObjectID = pSO->GetObjectID();
			}
			else
				WorldID = 0;
		}

		DE3D_STREAM_PUT(File, WorldID, u16); // deWorldID
		DE3D_STREAM_PUT(File, ObjectID, u32); // deObjectID
		
		i++;
		ptr = m_Objects.GetNext(ptr, pSO);
	}

	// number of portals
	length = m_PortalList.Length();
	DE3D_STREAM_PUT(File, length, s32);

	// the portals themselves
	ptr = m_PortalList.GetNext(NULL, pPortal);
	i = 0;
	while (ptr && i < length)
	{
		// link ID
		WorldID = pPortal->GetLinkWorldID();
		ObjectID= pPortal->GetLinkObjectID();
		DE3D_STREAM_PUT(File, WorldID, u16); // deWorldID
		DE3D_STREAM_PUT(File, ObjectID, u32); // deObjectID

		// position
		pPortal->GetPosition(Matrix);
		// 0.1 : DE3D_STREAM_PUT(File, Matrix, deTransformInfo);
		// 0.2:
		DE3D_STREAM_PUT(File, Matrix.Translation.x, deDouble);
		DE3D_STREAM_PUT(File, Matrix.Translation.y, deDouble);
		DE3D_STREAM_PUT(File, Matrix.Translation.z, deDouble);
		DE3D_STREAM_PUT(File, Matrix.R.x, deDouble);
		DE3D_STREAM_PUT(File, Matrix.R.y, deDouble);
		DE3D_STREAM_PUT(File, Matrix.R.z, deDouble);
		DE3D_STREAM_PUT(File, Matrix.U.x, deDouble);
		DE3D_STREAM_PUT(File, Matrix.U.y, deDouble);
		DE3D_STREAM_PUT(File, Matrix.U.z, deDouble);
		DE3D_STREAM_PUT(File, Matrix.I.x, deDouble);
		DE3D_STREAM_PUT(File, Matrix.I.y, deDouble);
		DE3D_STREAM_PUT(File, Matrix.I.z, deDouble);
		// transformation, if it needs it
		if (pPortal->IsTPortal())
		{
			DE3D_STREAM_PUT(File, TrueValue, u8);
			pPortal->GetTransform(Matrix);
			// 0.1 : DE3D_STREAM_PUT(File, Matrix, deTransformInfo);
			// 0.2:
			DE3D_STREAM_PUT(File, Matrix.Translation.x, deDouble);
			DE3D_STREAM_PUT(File, Matrix.Translation.y, deDouble);
			DE3D_STREAM_PUT(File, Matrix.Translation.z, deDouble);
			DE3D_STREAM_PUT(File, Matrix.R.x, deDouble);
			DE3D_STREAM_PUT(File, Matrix.R.y, deDouble);
			DE3D_STREAM_PUT(File, Matrix.R.z, deDouble);
			DE3D_STREAM_PUT(File, Matrix.U.x, deDouble);
			DE3D_STREAM_PUT(File, Matrix.U.y, deDouble);
			DE3D_STREAM_PUT(File, Matrix.U.z, deDouble);
			DE3D_STREAM_PUT(File, Matrix.I.x, deDouble);
			DE3D_STREAM_PUT(File, Matrix.I.y, deDouble);
			DE3D_STREAM_PUT(File, Matrix.I.z, deDouble);
		}
		else
		{
			DE3D_STREAM_PUT(File, FalseValue, u8);
		}

		// the normal of the portal
		pPortal->GetNormal(Vector);
		DE3D_STREAM_PUT(File, Vector.x, deDouble);
		DE3D_STREAM_PUT(File, Vector.y, deDouble);
		DE3D_STREAM_PUT(File, Vector.z, deDouble);
		
		// vertices making up the portal itself
		pVec = pPortal->GetVertices(k);
		DE3D_STREAM_PUT(File, k, s32);
		for (j = 0; j < k; j++)
		{
			DE3D_STREAM_PUT(File, pVec[j].x, deDouble);
			DE3D_STREAM_PUT(File, pVec[j].y, deDouble);
			DE3D_STREAM_PUT(File, pVec[j].z, deDouble);
		}

		i++;
		ptr = m_PortalList.GetNext(ptr, pPortal);
	}
		
	return deTRUE;
}

deBoolean deSceneRoom::DeSerialize(IdeFile* File, long DataLength)
{
	IdeSceneGraph*		pSG;
	IdePortal*			pPortal;
	deWorldID			WorldID;
	deObjectID			ObjectID;
	deTransformInfo		Matrix;
	deVec3d				Vector, *pVec;
	long				length, i, j, k;
	deBoolean			TempBool;
	short				VersionMajor, VersionMinor;
	u32					AmtRead = 0;

	// header information
	DE3D_STREAM_GET(File, VersionMajor, u16, AmtRead, DataLength);
	DE3D_STREAM_GET(File, VersionMinor, u16, AmtRead, DataLength);
	
	// first remove from the scenegraph if we're already inserted
	pSG = IdeSceneGraph_GetSceneGraphPtr();
	if (!pSG)
		return deFALSE;
	if (m_RoomListPtr)
		pSG->RemoveRoom(this);
	
	// check the version
	if (VersionMajor > deSceneRoom_Header.VersionMajor ||
		(VersionMajor == deSceneRoom_Header.VersionMajor && VersionMinor > deSceneRoom_Header.VersionMinor))
		return deFALSE;
	
	if (VersionMajor == 0 && (VersionMinor == 1 || VersionMinor == 2))
	{
		// AABB
		DE3D_STREAM_GET(File, m_Min.x, deDouble, AmtRead, DataLength);
		DE3D_STREAM_GET(File, m_Min.y, deDouble, AmtRead, DataLength);
		DE3D_STREAM_GET(File, m_Min.z, deDouble, AmtRead, DataLength);
		DE3D_STREAM_GET(File, m_Max.x, deDouble, AmtRead, DataLength);
		DE3D_STREAM_GET(File, m_Max.y, deDouble, AmtRead, DataLength);
		DE3D_STREAM_GET(File, m_Max.z, deDouble, AmtRead, DataLength);
		
		// number of scene objects
		DE3D_STREAM_GET(File, length, s32, AmtRead, DataLength);
		m_CachedObjects.Resize(length);
		
		// the objects themselves
		for (i = 0; i < length; ++i)
		{
			DE3D_STREAM_GET(File, WorldID, u16, AmtRead, DataLength); // deWorldID
			DE3D_STREAM_GET(File, ObjectID, u32, AmtRead, DataLength); // deObjectID

			m_CachedObjects[i].oid = ObjectID;
			m_CachedObjects[i].wid = WorldID;
		}

		// number of portals
		DE3D_STREAM_GET(File, length, s32, AmtRead, DataLength);
		// the portals themselves
		for (i = 0; i < length; ++i)
		{
			pPortal = IdePortal_CreatePortal();

			// link ID
			DE3D_STREAM_GET(File, WorldID, u16, AmtRead, DataLength); // deWorldID
			DE3D_STREAM_GET(File, ObjectID, u32, AmtRead, DataLength); // deObjectID
			pPortal->SetLinkWorldID(WorldID);
			pPortal->SetLinkObjectID(ObjectID);

			// position
			DE3D_STREAM_GET(File, Matrix.Translation.x, deDouble, AmtRead, DataLength);
			DE3D_STREAM_GET(File, Matrix.Translation.y, deDouble, AmtRead, DataLength);
			DE3D_STREAM_GET(File, Matrix.Translation.z, deDouble, AmtRead, DataLength);
			DE3D_STREAM_GET(File, Matrix.R.x, deDouble, AmtRead, DataLength);
			DE3D_STREAM_GET(File, Matrix.R.y, deDouble, AmtRead, DataLength);
			DE3D_STREAM_GET(File, Matrix.R.z, deDouble, AmtRead, DataLength);
			DE3D_STREAM_GET(File, Matrix.U.x, deDouble, AmtRead, DataLength);
			DE3D_STREAM_GET(File, Matrix.U.y, deDouble, AmtRead, DataLength);
			DE3D_STREAM_GET(File, Matrix.U.z, deDouble, AmtRead, DataLength);
			DE3D_STREAM_GET(File, Matrix.I.x, deDouble, AmtRead, DataLength);
			DE3D_STREAM_GET(File, Matrix.I.y, deDouble, AmtRead, DataLength);
			DE3D_STREAM_GET(File, Matrix.I.z, deDouble, AmtRead, DataLength);
			if (VersionMinor == 1)
			{
				// 0.1
				deDouble dummyval;
				DE3D_STREAM_GET(File, dummyval, deDouble, AmtRead, DataLength);
				DE3D_STREAM_GET(File, dummyval, deDouble, AmtRead, DataLength);
				DE3D_STREAM_GET(File, dummyval, deDouble, AmtRead, DataLength);
				DE3D_STREAM_GET(File, Matrix.m_Identity, u8, AmtRead, DataLength);
			}
			else if (VersionMinor == 2)
			{
				// 0.2
				((deTransform&)Matrix).TestIdentity();
			}
			pPortal->SetPosition(Matrix);
			// transformation, if it needs it
			DE3D_STREAM_GET(File, TempBool, u8, AmtRead, DataLength);
			if (TempBool)
			{
				DE3D_STREAM_GET(File, Matrix.Translation.x, deDouble, AmtRead, DataLength);
				DE3D_STREAM_GET(File, Matrix.Translation.y, deDouble, AmtRead, DataLength);
				DE3D_STREAM_GET(File, Matrix.Translation.z, deDouble, AmtRead, DataLength);
				DE3D_STREAM_GET(File, Matrix.R.x, deDouble, AmtRead, DataLength);
				DE3D_STREAM_GET(File, Matrix.R.y, deDouble, AmtRead, DataLength);
				DE3D_STREAM_GET(File, Matrix.R.z, deDouble, AmtRead, DataLength);
				DE3D_STREAM_GET(File, Matrix.U.x, deDouble, AmtRead, DataLength);
				DE3D_STREAM_GET(File, Matrix.U.y, deDouble, AmtRead, DataLength);
				DE3D_STREAM_GET(File, Matrix.U.z, deDouble, AmtRead, DataLength);
				DE3D_STREAM_GET(File, Matrix.I.x, deDouble, AmtRead, DataLength);
				DE3D_STREAM_GET(File, Matrix.I.y, deDouble, AmtRead, DataLength);
				DE3D_STREAM_GET(File, Matrix.I.z, deDouble, AmtRead, DataLength);
				if (VersionMinor == 1)
				{
					// 0.1
					deDouble dummyval;
					DE3D_STREAM_GET(File, dummyval, deDouble, AmtRead, DataLength);
					DE3D_STREAM_GET(File, dummyval, deDouble, AmtRead, DataLength);
					DE3D_STREAM_GET(File, dummyval, deDouble, AmtRead, DataLength);
					DE3D_STREAM_GET(File, Matrix.m_Identity, u8, AmtRead, DataLength);
				}
				else if (VersionMinor == 2)
				{
					// 0.2
					((deTransform&)Matrix).TestIdentity();
				}
				pPortal->SetTransform(Matrix);
			}

			// the normal of the portal
			DE3D_STREAM_GET(File, Vector.x, deDouble, AmtRead, DataLength);
			DE3D_STREAM_GET(File, Vector.y, deDouble, AmtRead, DataLength);
			DE3D_STREAM_GET(File, Vector.z, deDouble, AmtRead, DataLength);
			pPortal->SetNormal(Vector);
			
			// vertices making up the portal itself
			DE3D_STREAM_GET(File, k, s32, AmtRead, DataLength);
			pVec = new deVec3d[k];
			for (j = 0; j < k; j++)
			{
				DE3D_STREAM_GET(File, pVec[j].x, deDouble, AmtRead, DataLength);
				DE3D_STREAM_GET(File, pVec[j].y, deDouble, AmtRead, DataLength);
				DE3D_STREAM_GET(File, pVec[j].z, deDouble, AmtRead, DataLength);
			}
			pPortal->SetVertices(pVec, k);
			delete[] pVec;

			m_PortalList.AddElement(pPortal);
		}
	}

	if (!pSG->AddRoom(this))
		return deFALSE;
		
	return deTRUE;
}

deBoolean deSceneRoom::DeSerializeLoad()
{
	deWorldID			WorldID;
	deObjectID			ObjectID;
	IdeWorld*			pWorld;
	IdeWorldObject*		pObject;
	IdeSceneObject*		pSO;
	long				length, i;

	length = m_CachedObjects.Length();
	for (i = 0; i < length; ++i)
	{
		pSO = NULL;

		WorldID = m_CachedObjects[i].wid;
		ObjectID = m_CachedObjects[i].oid;

		pWorld = IdeWorld_GetManager()->GetWorld(((IdeWorldObject*)this)->GetWorldID());
		if (pWorld)
		{
			WorldID = pWorld->GetWorldIDUsingLocalID(WorldID, deFALSE);
			pWorld = IdeWorld_GetManager()->GetWorld(WorldID);
			if (pWorld)
			{
				pObject = pWorld->GetWorldObject(ObjectID);
				if (pObject)
				{
					pSO = (IdeSceneObject*)(pObject->GetWOInterface(IdeSceneObject_GetWOInterfaceID()));
				}
			}
		}
		if (pSO)
		{
			pSO->Claim();
			m_Objects.AddElement(pSO);
		}
	}

	return deTRUE;
}





//===================================================================
//
//===================================================================

IdeVertexBuffer *	deSceneSky::s_VBuffer = NULL;
IdeVertexBuffer *	deSceneSky::s_SubVBs[6] = {NULL,NULL,NULL,NULL,NULL,NULL};
long				deSceneSky::s_NumSkyRooms = 0;

deSceneSky::deSceneSky()
:	deSceneObject(iface_IdeSceneSky)
{
	s_NumSkyRooms++;
	memset(&m_Info, 0, sizeof(m_Info));
	memset(m_Textures, 0, 6*sizeof(IdeRenderTexture*));
	m_LockedToCam = deFALSE;
}

deSceneSky::~deSceneSky()
{
	int i;
	// release old stuff
	if (m_Info.type == SKY_BOX)
	{
		for (i = 0; i < 6; ++i)
		{
			m_Info.Box.Faces[i]->Release();
		}
	}
	else if (m_Info.type == SKY_DOME)
	{
	}
	else if (m_Info.type == SKY_SECTOR)
	{
	}

	for (i = 0; i < 6; ++i)
	{
		m_Textures[i]->Release();
	}

	s_NumSkyRooms--;
	if (s_NumSkyRooms == 0)
	{
		for (i = 0; i < 6; ++i)
		{
			if (s_SubVBs[i])
				s_SubVBs[i]->Release();
			s_SubVBs[i] = NULL;
		}
		if (s_VBuffer)
			s_VBuffer->Release();
		s_VBuffer = NULL;
	}
}

IdeSceneObject::interface_t deSceneSky::GetSOIType()
{
	return iface_IdeSceneSky;
}

void* deSceneSky::GetSOInterface(interface_t i)
{
	if (i == iface_IdeSceneSky)
	{
		return (IdeSceneSky*)(this);
	}
	if (i == iface_IdeSceneObject)
	{
		return (IdeSceneObject*)(this);
	}
	return NULL;
}

void deSceneSky::OnWorldIDSet()
{
	CreateTextures();
	int i;
	for (i = 0; i < 6; ++i)
	{
		m_Textures[i]->SetWorldID(GetWorldID());
	}
}

deBoolean deSceneSky::IsLockedToCam() const
{
	return m_LockedToCam;
}

void deSceneSky::LockToCam(deBoolean Lock)
{
	m_LockedToCam = Lock;
}
	
deBoolean deSceneSky::GetInfo(SkyInfo * info) const
{
	if (!info)
		DEBUGRETURN(deFALSE, "GetInfo: NULL parameter: info");

	*info = m_Info;
	return deTRUE;
}

deBoolean deSceneSky::SetInfo(const SkyInfo * info)
{
	if (!info)
		DEBUGRETURN(deFALSE, "SetInfo: NULL parameter: info");

	// we claim first then release because some might be re-used
	
	// claim new stuff
	if (info->type == SKY_BOX)
	{
		if (info->Box.FaceNames.NegX)
			info->Box.FaceNames.NegX->Claim();
		if (info->Box.FaceNames.NegY)
			info->Box.FaceNames.NegY->Claim();
		if (info->Box.FaceNames.NegZ)
			info->Box.FaceNames.NegZ->Claim();
		if (info->Box.FaceNames.PosX)
			info->Box.FaceNames.PosX->Claim();
		if (info->Box.FaceNames.PosY)
			info->Box.FaceNames.PosY->Claim();
		if (info->Box.FaceNames.PosZ)
			info->Box.FaceNames.PosZ->Claim();
	}
	else if (info->type == SKY_DOME)
	{
	}
	else if (info->type == SKY_SECTOR)
	{
	}

	// release old stuff
	if (m_Info.type == SKY_BOX)
	{
		if (m_Info.Box.FaceNames.NegX)
			m_Info.Box.FaceNames.NegX->Release();
		if (m_Info.Box.FaceNames.NegY)
			m_Info.Box.FaceNames.NegY->Release();
		if (m_Info.Box.FaceNames.NegZ)
			m_Info.Box.FaceNames.NegZ->Release();
		if (m_Info.Box.FaceNames.PosX)
			m_Info.Box.FaceNames.PosX->Release();
		if (m_Info.Box.FaceNames.PosY)
			m_Info.Box.FaceNames.PosY->Release();
		if (m_Info.Box.FaceNames.PosZ)
			m_Info.Box.FaceNames.PosZ->Release();
	}
	else if (m_Info.type == SKY_DOME)
	{
	}
	else if (m_Info.type == SKY_SECTOR)
	{
	}

	// make assignment to our member variable
	m_Info = *info;

	if (!CreateTextures())
		DEBUGRETURN(deFALSE, "SetInfo: failed to create textures");

	return deTRUE;
}

#pragma todo (finish deSceneSky::TraverseForRender)
long deSceneSky::TraverseForRender(IdeSceneGraph::deSceneTraversal* Params)
{
	//	return 0;
	
	if (!s_VBuffer)
	{
		if (!CreateVBuffers())
			DEBUGRETURN(0, "deSceneSky::TraverseForRender: failed to create vertex buffer");
	}
	if (!m_Textures[0])
	{
		if (!CreateTextures())
			DEBUGRETURN(0, "deSceneSky::TraverseForRender: failed to create textures");
	}
	
	int i;
	IdeRender::deRenderObject obj;
	deTransform tform;
	tform.Translation = Params->cam->Position().Translation;
	memset(&obj, 0, sizeof(IdeRender::deRenderObject));
	obj.Transform = tform;
	obj.isSky = deTRUE;
	
	for (i = 0; i < 6; ++i)
	{
		obj.VB = s_SubVBs[i];
		obj.SurfaceDetail.Texture = m_Textures[i];
		Params->render->RenderPrepBuffer(obj);
	}
	
	return 0;
}

deBoolean deSceneSky::CreateVBuffers()
{
	if (!s_VBuffer)
	{
		s_VBuffer = IdeVertexBuffer_CreateVBuffer();
		if (!s_VBuffer)
			return deFALSE;
	}

	int				i;
	deVertex *		PosBuffer;
	deTexCoord *	CoordBuffer;
	unsigned short*	IndexBuffer;

	s_VBuffer->Lock();
	s_VBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_POSITION, deFALSE);
	s_VBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_TEXTURECOORDS0, deFALSE);
	s_VBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_INDICES16, deFALSE);
	s_VBuffer->Unlock();

	for (i = 0; i < 6; ++i)
	{
		if (s_SubVBs[i])
			s_SubVBs[i]->Release();

		s_SubVBs[i] = IdeVertexBuffer_CreateSubVBuffer(s_VBuffer);
		if (!s_SubVBs[i])
			return deFALSE;

		s_SubVBs[i]->Lock();
		s_SubVBs[i]->SetBufferSize(4, deFALSE);		// vertices
		s_SubVBs[i]->SetBufferSize(2*3, deTRUE);	// indices
		s_SubVBs[i]->Unlock();
	}

	static const deVertex StaticPos[24] = 
	{	{-1, 1,-1}, // NegX
		{-1,-1,-1},
		{-1, 1, 1},
		{-1,-1, 1},

		{-1,-1, 1}, // NegY
		{-1,-1,-1},
		{ 1,-1, 1},
		{ 1,-1,-1},

		{ 1, 1,-1}, // NegZ
		{ 1,-1,-1},
		{-1, 1,-1},
		{-1,-1,-1},

		{ 1, 1, 1}, // PosX
		{ 1,-1, 1},
		{ 1, 1,-1},
		{ 1,-1,-1},

		{-1, 1,-1}, // PosY
		{-1, 1, 1},
		{ 1, 1,-1},
		{ 1, 1, 1},

		{-1, 1, 1}, // PosZ
		{-1,-1, 1},
		{ 1, 1, 1},
		{ 1,-1, 1}	};

	static const deTexCoord StaticCoord[4] = 
	{	{0,0},
		{0,1},
		{1,0},
		{1,1}	};

	for (i = 0; i < 6; ++i)
	{
		if (!s_SubVBs[i]->Lock())
			return deFALSE;
		PosBuffer = (deVertex*)(s_SubVBs[i]->GetBuffer(IdeVertexBuffer::BUFFER_POSITION));
		CoordBuffer = (deTexCoord*)(s_SubVBs[i]->GetBuffer(IdeVertexBuffer::BUFFER_TEXTURECOORDS0));
		IndexBuffer = (unsigned short*)(s_SubVBs[i]->GetBuffer(IdeVertexBuffer::BUFFER_INDICES16));
		
		if (!PosBuffer || !CoordBuffer || !IndexBuffer)
		{
			s_SubVBs[i]->Unlock();
			return deFALSE;
		}

		PosBuffer[0] = StaticPos[i*4    ];
		PosBuffer[1] = StaticPos[i*4 + 1];
		PosBuffer[2] = StaticPos[i*4 + 2];
		PosBuffer[3] = StaticPos[i*4 + 3];

		CoordBuffer[0] = StaticCoord[0];
		CoordBuffer[1] = StaticCoord[1];
		CoordBuffer[2] = StaticCoord[2];
		CoordBuffer[3] = StaticCoord[3];

		IndexBuffer[0] = 0;
		IndexBuffer[1] = 1;
		IndexBuffer[2] = 2;
		IndexBuffer[3] = 2;
		IndexBuffer[4] = 1;
		IndexBuffer[5] = 3;

		s_SubVBs[i]->SetRenderType(IdeVertexBuffer::RENDER_TRIANGLELIST);
		
		s_SubVBs[i]->Unlock();
	}

	return deTRUE;
}

deBoolean deSceneSky::CreateTextures()
{
	int i;
	for (i = 0; i < 6; ++i)
	{
		if (!m_Textures[i])
		{
			m_Textures[i] = IdeRenderState_CreateRenderTexture();
			if (!m_Textures[i])
				return deFALSE;
			
			m_Textures[i]->Lock();

			m_Textures[i]->SetColorArg(0, 1, IdeRenderTexture::TEXTUREARG_TEXTURE);
			m_Textures[i]->SetColorOperation(0, IdeRenderTexture::TEXTUREOP_SELECTARG1);
			m_Textures[i]->SetAlphaOperation(0, IdeRenderTexture::TEXTUREOP_DISABLE);
			m_Textures[i]->SetColorOperation(1, IdeRenderTexture::TEXTUREOP_DISABLE);
			m_Textures[i]->SetAlphaOperation(1, IdeRenderTexture::TEXTUREOP_DISABLE);
			m_Textures[i]->SetTextureMagFilter(0, IdeRenderTexture::TEXTUREFILTER_LINEAR);
			m_Textures[i]->SetTextureMinFilter(0, IdeRenderTexture::TEXTUREFILTER_LINEAR);
			m_Textures[i]->SetTextureMipFilter(0, IdeRenderTexture::TEXTUREFILTER_POINT);
			m_Textures[i]->SetTextureAddressU(0, IdeRenderTexture::TEXTUREADDRESS_CLAMP);
			m_Textures[i]->SetTextureAddressV(0, IdeRenderTexture::TEXTUREADDRESS_CLAMP);
		}
		else
		{
			m_Textures[i]->Lock();
		}
		if (m_Info.type == SKY_BOX)
			m_Textures[i]->SetBitmap(0, m_Info.Box.Faces[i]);
		else
			m_Textures[i]->SetBitmap(0, NULL);

		m_Textures[i]->Unlock();
	}
	return deTRUE;
}

deBoolean deSceneSky::TestRoomCollision(const IdeCollision::deCollideParams & /*Params*/, IdeCollision * /*Collision*/)
{
	// this is intentional - you can't hit the sky
	return deFALSE;
}

deBoolean deSceneSky::Serialize(IdeFile* File)
{
	if (!deSceneObject::Serialize(File))
		return deFALSE;
	
#pragma todo (write sky info)
	return deTRUE;
}

deBoolean deSceneSky::DeSerialize(IdeFile* File, long DataLength)
{
	u32 AmtRead = 0;
	if (!deSceneObject::DeSerialize(File, DataLength, AmtRead))
		return deFALSE;
	
#pragma todo (read sky info)
	return deTRUE;
}

deBoolean deSceneSky::DeSerializeLoad()
{
	if (!deSceneObject::DeSerializeLoad())
		return deFALSE;
	
#pragma todo (resolve sky info)
	return deTRUE;
}





deSceneABT::deSceneABT()
:	deSceneObject(iface_IdeSceneABT)
{
	m_Compiled = deFALSE;
	m_ABT.SetSplitWeights(0.25, 0.25, 0.25, 0.25);

// testing stuff
	if (0)
	{
		long k;
		dePolyABT::ABTVertex	VertArray[12];
		long					IndexArray[] = 
		{
			0,1,2, 0,2,3,
				4,5,6, 4,6,7,
				8,9,10, 8,10,11,
				0,1,5, 0,5,4,
				4,5,9, 4,9,8,
		};
		memset(VertArray, 0, sizeof(VertArray));
		VertArray[0].Position = deMake_Vec3d(0,0,10);
		VertArray[1].Position = deMake_Vec3d(0,10,10);
		VertArray[2].Position = deMake_Vec3d(10,10,10);
		VertArray[3].Position = deMake_Vec3d(10,0,10);
		VertArray[4].Position = deMake_Vec3d(0,0,0);
		VertArray[5].Position = deMake_Vec3d(0,10,0);
		VertArray[6].Position = deMake_Vec3d(10,10,0);
		VertArray[7].Position = deMake_Vec3d(10,0,0);
		VertArray[8 ].Position = deMake_Vec3d(0,0,-10);
		VertArray[9 ].Position = deMake_Vec3d(0,10,-10);
		VertArray[10].Position = deMake_Vec3d(10,10,-10);
		VertArray[11].Position = deMake_Vec3d(10,0,-10);
		//ABT.SetSplitWeights(0.125, 0.125, 0.5, 0.25);
		//m_ABT.SetMaxLeafTris(8);
		deTransform pos;
		pos.Reset(); // identity
		m_ABT.AddVertices(VertArray, sizeof(VertArray)/sizeof(dePolyABT::ABTVertex), k, pos);
		m_ABT.AddTriangleIndices(IndexArray, k, sizeof(IndexArray)/sizeof(long));
		m_ABT.CompileABT();
	}
}

deSceneABT::~deSceneABT()
{
}

IdeSceneObject::interface_t deSceneABT::GetSOIType()
{
	return iface_IdeSceneABT;
}

void* deSceneABT::GetSOInterface(interface_t i)
{
	if (i == iface_IdeSceneABT)
	{
		return (IdeSceneABT*)(this);
	}
	if (i == iface_IdeSceneObject)
	{
		return (IdeSceneObject*)(this);
	}
	return NULL;
}

deBoolean deSceneABT::AddGeometry(IdeMesh* pMesh, const deTransformInfo & pos)
{
	m_Compiled = deFALSE;
	if (!m_ABT.AddMeshGeometry(pMesh, pos))
		return deFALSE;
	deAABB bbox;
	m_ABT.GetVisibleAABB(bbox);
	SetLocalAABB(bbox.Min, bbox.Max);
	SetBoundCenter(deZeroVec);
	deDouble r1 = Vec3d_Length(bbox.Min);
	deDouble r2 = Vec3d_Length(bbox.Max);
	r1 = max(r1,r2);
	SetBoundRadius(r1);
	return deTRUE;
}

long deSceneABT::TraverseForRender(IdeSceneGraph::deSceneTraversal* Params)
{
	if (!m_Compiled)
	{
		m_ABT.CompileABT();
		m_Compiled = deTRUE;
	}
	m_ABT.RenderVisibleGeometry(Params);

	return 0;
}

deBoolean deSceneABT::TestRoomCollision(const IdeCollision::deCollideParams & /*Params*/, IdeCollision * /*Collision*/)
{
#pragma todo (implement deSceneABT::TestRoomCollision)
	return deFALSE;
}

deBoolean deSceneABT::Serialize(IdeFile* File)
{
	if (!deSceneObject::Serialize(File))
		return deFALSE;

	if (!m_Compiled)
		m_ABT.CompileABT();
	
	if (!m_ABT.Serialize(File))
		return deFALSE;
	
	return deTRUE;
}

deBoolean deSceneABT::DeSerialize(IdeFile* File, long DataLength)
{
	u32 AmtRead = 0;
	if (!deSceneObject::DeSerialize(File, DataLength, AmtRead))
		return deFALSE;

	if (!m_ABT.DeSerialize(File, DataLength, AmtRead))
		return deFALSE;

	// it should be precompiled in the file
	m_Compiled = deTRUE;
	
	return deTRUE;
}

deBoolean deSceneABT::DeSerializeLoad()
{
	if (!deSceneObject::DeSerializeLoad())
		return deFALSE;
	
	if (!m_ABT.DeSerializeLoad())
		return deFALSE;
	
	return deTRUE;
}

